201 "Socket closed");
202 return;
203 } else {
204 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
205 }
206
207 if (IS_NULL(iaObj)) {
208 JNU_ThrowNullPointerException(env, "iaObj is null.");
209 return;
210 }
211
212 /* bind */
213 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
214 return;
215 }
216 setDefaultScopeID(env, (struct sockaddr *)&him);
217
218 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
219 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
220 errno == EPERM || errno == EACCES) {
221 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
222 "Bind failed");
223 } else {
224 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
225 "Bind failed");
226 }
227 return;
228 }
229
230 /* initialize the local port */
231 if (localport == 0) {
232 /* Now that we're a connected socket, let's extract the port number
233 * that the system chose for us and store it in the Socket object.
234 */
235 if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) {
236 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
237 "Error getting socket name");
238 return;
239 }
240
241 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
242
243 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
244 } else {
245 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
246 }
247 }
248
249 /*
250 * Class: java_net_PlainDatagramSocketImpl
251 * Method: connect0
252 * Signature: (Ljava/net/InetAddress;I)V
253 */
254 JNIEXPORT void JNICALL
255 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
256 jobject address, jint port) {
257 /* The object's field */
264
265 if (IS_NULL(fdObj)) {
266 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
267 "Socket closed");
268 return;
269 }
270 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
271
272 if (IS_NULL(address)) {
273 JNU_ThrowNullPointerException(env, "address");
274 return;
275 }
276
277 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
278 return;
279 }
280
281 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
282
283 if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
284 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
285 "Connect failed");
286 return;
287 }
288
289 }
290
291 /*
292 * Class: java_net_PlainDatagramSocketImpl
293 * Method: disconnect0
294 * Signature: ()V
295 */
296 JNIEXPORT void JNICALL
297 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
298 /* The object's field */
299 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
300 /* The fdObj'fd */
301 jint fd;
302
303 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
304 SOCKADDR addr;
305 socklen_t len;
452 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
453 }
454 #endif /* AF_INET6 */
455
456
457 /*
458 * Send the datagram.
459 *
460 * If we are connected it's possible that sendto will return
461 * ECONNREFUSED indicating that an ICMP port unreachable has
462 * received.
463 */
464 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
465 (struct sockaddr *)rmtaddrP, len);
466
467 if (ret < 0) {
468 if (errno == ECONNREFUSED) {
469 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
470 "ICMP Port Unreachable");
471 } else {
472 NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
473 }
474 }
475
476 if (mallocedPacket) {
477 free(fullPacket);
478 }
479 return;
480 }
481
482 /*
483 * Class: java_net_PlainDatagramSocketImpl
484 * Method: peek
485 * Signature: (Ljava/net/InetAddress;)I
486 */
487 JNIEXPORT jint JNICALL
488 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
489 jobject addressObj) {
490
491 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
492 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
503 return -1;
504 } else {
505 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
506 }
507 if (IS_NULL(addressObj)) {
508 JNU_ThrowNullPointerException(env, "Null address in peek()");
509 return -1;
510 }
511 if (timeout) {
512 int ret = NET_Timeout(fd, timeout);
513 if (ret == 0) {
514 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
515 "Peek timed out");
516 return ret;
517 } else if (ret == -1) {
518 if (errno == EBADF) {
519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
520 } else if (errno == ENOMEM) {
521 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
522 } else {
523 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
524 }
525 return ret;
526 }
527 }
528
529 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);
530
531 if (n == -1) {
532
533 #ifdef __solaris__
534 if (errno == ECONNREFUSED) {
535 int orig_errno = errno;
536 (void) recv(fd, buf, 1, 0);
537 errno = orig_errno;
538 }
539 #endif
540 if (errno == ECONNREFUSED) {
541 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
542 "ICMP Port Unreachable");
543 } else {
544 if (errno == EBADF) {
545 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
546 } else {
547 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
548 }
549 }
550 return 0;
551 }
552
553 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
554 #ifdef AF_INET6
555 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
556 #else
557 family = AF_INET;
558 #endif
559 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
560 int address = getInetAddress_addr(env, iaObj);
561 setInetAddress_addr(env, addressObj, address);
562 }
563 return port;
564 }
565
566 JNIEXPORT jint JNICALL
567 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
599 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
600 if (IS_NULL(packetBuffer)) {
601 JNU_ThrowNullPointerException(env, "packet buffer");
602 return -1;
603 }
604 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
605 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
606 if (timeout) {
607 int ret = NET_Timeout(fd, timeout);
608 if (ret == 0) {
609 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
610 "Receive timed out");
611 return -1;
612 } else if (ret == -1) {
613 if (errno == ENOMEM) {
614 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
615 #ifdef __linux__
616 } else if (errno == EBADF) {
617 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
618 } else {
619 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
620 #else
621 } else {
622 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
623 #endif
624 }
625 return -1;
626 }
627 }
628
629 if (packetBufferLen > MAX_BUFFER_LEN) {
630
631 /* When JNI-ifying the JDK's IO routines, we turned
632 * reads and writes of byte arrays of size greater
633 * than 2048 bytes into several operations of size 2048.
634 * This saves a malloc()/memcpy()/free() for big
635 * buffers. This is OK for file IO and TCP, but that
636 * strategy violates the semantics of a datagram protocol.
637 * (one big send) != (several smaller sends). So here
638 * we *must* allocate the buffer. Note it needn't be bigger
639 * than 65,536 (0xFFFF), the max size of an IP packet.
664 n = packetBufferLen;
665 }
666 if (n == -1) {
667
668 #ifdef __solaris__
669 if (errno == ECONNREFUSED) {
670 int orig_errno = errno;
671 (void) recv(fd, fullPacket, 1, 0);
672 errno = orig_errno;
673 }
674 #endif
675 (*env)->SetIntField(env, packet, dp_offsetID, 0);
676 (*env)->SetIntField(env, packet, dp_lengthID, 0);
677 if (errno == ECONNREFUSED) {
678 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
679 "ICMP Port Unreachable");
680 } else {
681 if (errno == EBADF) {
682 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
683 } else {
684 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
685 }
686 }
687 } else {
688 /*
689 * success - fill in received address...
690 *
691 * REMIND: Fill in an int on the packet, and create inetadd
692 * object in Java, as a performance improvement. Also
693 * construct the inetadd object lazily.
694 */
695
696 jobject packetAddress;
697
698 /*
699 * Check if there is an InetAddress already associated with this
700 * packet. If so we check if it is the same source address. We
701 * can't update any existing InetAddress because it is immutable
702 */
703 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
704 if (packetAddress != NULL) {
810 } else {
811 fullPacket = &(BUF[0]);
812 }
813
814 do {
815 retry = JNI_FALSE;
816
817 if (timeout) {
818 int ret = NET_Timeout(fd, timeout);
819 if (ret <= 0) {
820 if (ret == 0) {
821 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
822 "Receive timed out");
823 } else if (ret == -1) {
824 if (errno == ENOMEM) {
825 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
826 #ifdef __linux__
827 } else if (errno == EBADF) {
828 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
829 } else {
830 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
831 #else
832 } else {
833 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
834 #endif
835 }
836 }
837
838 if (mallocedPacket) {
839 free(fullPacket);
840 }
841
842 return;
843 }
844 }
845
846 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
847 (struct sockaddr *)&remote_addr, &slen);
848 /* truncate the data if the packet's length is too small */
849 if (n > packetBufferLen) {
850 n = packetBufferLen;
851 }
852 if (n == -1) {
853 (*env)->SetIntField(env, packet, dp_offsetID, 0);
854 (*env)->SetIntField(env, packet, dp_lengthID, 0);
855 if (errno == ECONNREFUSED) {
856 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
857 "ICMP Port Unreachable");
858 } else {
859 if (errno == EBADF) {
860 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
861 } else {
862 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
863 }
864 }
865 } else {
866 int port;
867 jobject packetAddress;
868
869 /*
870 * success - fill in received address...
871 *
872 * REMIND: Fill in an int on the packet, and create inetadd
873 * object in Java, as a performance improvement. Also
874 * construct the inetadd object lazily.
875 */
876
877 /*
878 * Check if there is an InetAddress already associated with this
879 * packet. If so we check if it is the same source address. We
880 * can't update any existing InetAddress because it is immutable
881 */
882 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
915 */
916 JNIEXPORT void JNICALL
917 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
918 jobject this) {
919 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
920 int arg, fd, t = 1;
921 char tmpbuf[1024];
922 #ifdef AF_INET6
923 int domain = ipv6_available() ? AF_INET6 : AF_INET;
924 #else
925 int domain = AF_INET;
926 #endif
927
928 if (IS_NULL(fdObj)) {
929 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
930 "Socket closed");
931 return;
932 }
933
934 if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
935 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
936 "Error creating socket");
937 return;
938 }
939
940 #ifdef AF_INET6
941 /* Disable IPV6_V6ONLY to ensure dual-socket support */
942 if (domain == AF_INET6) {
943 arg = 0;
944 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
945 sizeof(int)) < 0) {
946 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
947 close(fd);
948 return;
949 }
950 }
951 #endif /* AF_INET6 */
952
953 #ifdef __APPLE__
954 arg = 65507;
955 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
956 (char *)&arg, sizeof(arg)) < 0) {
1063 */
1064 if (len < 1) {
1065 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1066 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1067 return;
1068 }
1069
1070 /*
1071 * We need an ipv4 address here
1072 */
1073 for (i = 0; i < len; i++) {
1074 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1075 if (getInetAddress_family(env, addr) == IPv4) {
1076 in.s_addr = htonl(getInetAddress_addr(env, addr));
1077 break;
1078 }
1079 }
1080
1081 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1082 (const char*)&in, sizeof(in)) < 0) {
1083 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1084 "Error setting socket option");
1085 }
1086 }
1087
1088 /*
1089 * Set outgoing multicast interface designated by a NetworkInterface.
1090 * Throw exception if failed.
1091 */
1092 #ifdef AF_INET6
1093 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1094 static jfieldID ni_indexID;
1095 int index;
1096
1097 if (ni_indexID == NULL) {
1098 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1099 CHECK_NULL(c);
1100 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1101 CHECK_NULL(ni_indexID);
1102 }
1103 index = (*env)->GetIntField(env, value, ni_indexID);
1104
1105 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1106 (const char*)&index, sizeof(index)) < 0) {
1107 if (errno == EINVAL && index > 0) {
1108 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1109 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1110 "address only?)");
1111 } else {
1112 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1113 "Error setting socket option");
1114 }
1115 return;
1116 }
1117
1118 }
1119 #endif /* AF_INET6 */
1120
1121 /*
1122 * Set outgoing multicast interface designated by an InetAddress.
1123 * Throw exception if failed.
1124 */
1125 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1126 struct in_addr in;
1127
1128 in.s_addr = htonl( getInetAddress_addr(env, value) );
1129
1130 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1131 (const char*)&in, sizeof(in)) < 0) {
1132 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1133 "Error setting socket option");
1134 }
1135 }
1136
1137 /*
1138 * Set outgoing multicast interface designated by an InetAddress.
1139 * Throw exception if failed.
1140 */
1141 #ifdef AF_INET6
1142 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1143 static jclass ni_class;
1144 if (ni_class == NULL) {
1145 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1146 CHECK_NULL(c);
1147 ni_class = (*env)->NewGlobalRef(env, c);
1148 CHECK_NULL(ni_class);
1149 }
1150
1151 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1152 if (value == NULL) {
1153 if (!(*env)->ExceptionOccurred(env)) {
1239 }
1240 }
1241
1242 /*
1243 * Enable/disable local loopback of multicast datagrams.
1244 */
1245 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1246 jclass cls;
1247 jfieldID fid;
1248 jboolean on;
1249 char loopback;
1250
1251 cls = (*env)->FindClass(env, "java/lang/Boolean");
1252 CHECK_NULL(cls);
1253 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1254 CHECK_NULL(fid);
1255
1256 on = (*env)->GetBooleanField(env, value, fid);
1257 loopback = (!on ? 1 : 0);
1258
1259 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&loopback, sizeof(char)) < 0) {
1260 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1261 return;
1262 }
1263 }
1264
1265 /*
1266 * Enable/disable local loopback of multicast datagrams.
1267 */
1268 #ifdef AF_INET6
1269 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1270 jclass cls;
1271 jfieldID fid;
1272 jboolean on;
1273 int loopback;
1274
1275 cls = (*env)->FindClass(env, "java/lang/Boolean");
1276 CHECK_NULL(cls);
1277 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1278 CHECK_NULL(fid);
1279
1280 on = (*env)->GetBooleanField(env, value, fid);
1281 loopback = (!on ? 1 : 0);
1282
1283 if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&loopback, sizeof(int)) < 0) {
1284 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1285 return;
1286 }
1287
1288 }
1289 #endif /* AF_INET6 */
1290
1291 /*
1292 * Sets the multicast loopback mode.
1293 */
1294 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
1295 jint opt, jobject value) {
1296 #ifdef AF_INET6
1297 #ifdef __linux__
1298 mcast_set_loop_v4(env, this, fd, value);
1299 if (ipv6_available()) {
1300 if ((*env)->ExceptionCheck(env)){
1301 (*env)->ExceptionClear(env);
1302 }
1303 mcast_set_loop_v6(env, this, fd, value);
1304 }
1403 CHECK_NULL(cls);
1404 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1405 CHECK_NULL(fid);
1406
1407 on = (*env)->GetBooleanField(env, value, fid);
1408
1409 /* SO_REUSEADDR or SO_BROADCAST */
1410 optval = (on ? 1 : 0);
1411
1412 break;
1413 }
1414
1415 default :
1416 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1417 "Socket option not supported by PlainDatagramSocketImp");
1418 return;
1419
1420 }
1421
1422 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1423 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1424 return;
1425 }
1426 }
1427
1428
1429 /*
1430 * Return the multicast interface:
1431 *
1432 * SocketOptions.IP_MULTICAST_IF
1433 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1434 * Create InetAddress
1435 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1436 * kernel but struct in_addr on 2.4 kernel
1437 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1438 * If index == 0 return InetAddress representing
1439 * anyLocalAddress.
1440 * If index > 0 query NetworkInterface by index
1441 * and returns addrs[0]
1442 *
1443 * SocketOptions.IP_MULTICAST_IF2
1466 static jclass inet4_class;
1467 static jmethodID inet4_ctrID;
1468
1469 static jclass ni_class;
1470 static jmethodID ni_ctrID;
1471 static jfieldID ni_indexID;
1472 static jfieldID ni_addrsID;
1473 static jfieldID ni_nameID;
1474
1475 jobjectArray addrArray;
1476 jobject addr;
1477 jobject ni;
1478 jobject ni_name;
1479
1480 struct in_addr in;
1481 struct in_addr *inP = ∈
1482 socklen_t len = sizeof(struct in_addr);
1483
1484 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1485 (char *)inP, &len) < 0) {
1486 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1487 "Error getting socket option");
1488 return NULL;
1489 }
1490
1491 /*
1492 * Construct and populate an Inet4Address
1493 */
1494 if (inet4_class == NULL) {
1495 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1496 CHECK_NULL_RETURN(c, NULL);
1497 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1498 CHECK_NULL_RETURN(inet4_ctrID, NULL);
1499 inet4_class = (*env)->NewGlobalRef(env, c);
1500 CHECK_NULL_RETURN(inet4_class, NULL);
1501 }
1502 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1503 CHECK_NULL_RETURN(addr, NULL);
1504
1505 setInetAddress_addr(env, addr, ntohl(in.s_addr));
1506
1507 /*
1564 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1565
1566 static jclass ni_class;
1567 static jmethodID ni_ctrID;
1568 static jfieldID ni_indexID;
1569 static jfieldID ni_addrsID;
1570 static jclass ia_class;
1571 static jfieldID ni_nameID;
1572 static jmethodID ia_anyLocalAddressID;
1573
1574 int index = 0;
1575 socklen_t len = sizeof(index);
1576
1577 jobjectArray addrArray;
1578 jobject addr;
1579 jobject ni;
1580 jobject ni_name;
1581
1582 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1583 (char*)&index, &len) < 0) {
1584 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1585 "Error getting socket option");
1586 return NULL;
1587 }
1588
1589 if (ni_class == NULL) {
1590 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1591 CHECK_NULL_RETURN(c, NULL);
1592 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1593 CHECK_NULL_RETURN(ni_ctrID, NULL);
1594 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1595 CHECK_NULL_RETURN(ni_indexID, NULL);
1596 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1597 "[Ljava/net/InetAddress;");
1598 CHECK_NULL_RETURN(ni_addrsID, NULL);
1599
1600 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1601 CHECK_NULL_RETURN(ia_class, NULL);
1602 ia_class = (*env)->NewGlobalRef(env, ia_class);
1603 CHECK_NULL_RETURN(ia_class, NULL);
1604 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1605 ia_class,
1709 */
1710 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1711 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1712 return getMulticastInterface(env, this, fd, opt);
1713
1714 }
1715
1716 /*
1717 * SO_BINDADDR implemented using getsockname
1718 */
1719 if (opt == java_net_SocketOptions_SO_BINDADDR) {
1720 /* find out local IP address */
1721 SOCKADDR him;
1722 socklen_t len = 0;
1723 int port;
1724 jobject iaObj;
1725
1726 len = SOCKADDR_LEN;
1727
1728 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
1729 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1730 "Error getting socket name");
1731 return NULL;
1732 }
1733 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1734
1735 return iaObj;
1736 }
1737
1738 /*
1739 * Map the Java level socket option to the platform specific
1740 * level and option name.
1741 */
1742 if (NET_MapSocketOption(opt, &level, &optname)) {
1743 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1744 return NULL;
1745 }
1746
1747 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1748 level == IPPROTO_IP) {
1749 optlen = sizeof(optval.c);
1750 } else {
1751 optlen = sizeof(optval.i);
1752 }
1753
1754 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1755 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1756 "Error getting socket option");
1757 return NULL;
1758 }
1759
1760 switch (opt) {
1761 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1762 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
1763 if (level == IPPROTO_IP) {
1764 return createBoolean(env, (int)!optval.c);
1765 } else {
1766 return createBoolean(env, !optval.i);
1767 }
1768
1769 case java_net_SocketOptions_SO_BROADCAST:
1770 case java_net_SocketOptions_SO_REUSEADDR:
1771 return createBoolean(env, optval.i);
1772
1773 case java_net_SocketOptions_SO_REUSEPORT:
1774 return createBoolean(env, optval.i);
1775
1776 case java_net_SocketOptions_SO_SNDBUF:
1788 * Multicast-related calls
1789 */
1790
1791 JNIEXPORT void JNICALL
1792 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1793 jbyte ttl) {
1794 jint ittl = ttl;
1795 if (ittl < 0) {
1796 ittl += 0x100;
1797 }
1798 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1799 }
1800
1801 /*
1802 * Set TTL for a socket. Throw exception if failed.
1803 */
1804 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1805 char ittl = (char)ttl;
1806 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1807 sizeof(ittl)) < 0) {
1808 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1809 "Error setting socket option");
1810 }
1811 }
1812
1813 /*
1814 * Set hops limit for a socket. Throw exception if failed.
1815 */
1816 #ifdef AF_INET6
1817 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1818 int ittl = (int)ttl;
1819 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1820 (char*)&ittl, sizeof(ittl)) < 0) {
1821 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1822 "Error setting socket option");
1823 }
1824 }
1825 #endif
1826
1827 /*
1828 * Class: java_net_PlainDatagramSocketImpl
1829 * Method: setTTL
1830 * Signature: (B)V
1831 */
1832 JNIEXPORT void JNICALL
1833 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1834 jint ttl) {
1835
1836 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1837 int fd;
1838 /* it is important to cast this to a char, otherwise setsockopt gets confused */
1839
1840 if (IS_NULL(fdObj)) {
1841 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1842 "Socket closed");
1884 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1885
1886 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1887 jint fd = -1;
1888
1889 if (IS_NULL(fdObj)) {
1890 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1891 "Socket closed");
1892 return -1;
1893 } else {
1894 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1895 }
1896 /* getsockopt of TTL */
1897 #ifdef AF_INET6
1898 if (ipv6_available()) {
1899 int ttl = 0;
1900 socklen_t len = sizeof(ttl);
1901
1902 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1903 (char*)&ttl, &len) < 0) {
1904 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1905 "Error getting socket option");
1906 return -1;
1907 }
1908 return (jint)ttl;
1909 } else
1910 #endif /* AF_INET6 */
1911 {
1912 u_char ttl = 0;
1913 socklen_t len = sizeof(ttl);
1914 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1915 (char*)&ttl, &len) < 0) {
1916 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1917 "Error getting socket option");
1918 return -1;
1919 }
1920 return (jint)ttl;
1921 }
1922 }
1923
1924
1925 /*
1926 * mcast_join_leave: Join or leave a multicast group.
1927 *
1928 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1929 * to join/leave multicast group.
1930 *
1931 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1932 * to join/leave multicast group. If multicast group is an IPv4 address then
1933 * an IPv4-mapped address is used.
1934 *
1935 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1936 * we must use the IPv4 socket options. This is because the IPv6 socket options
1937 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
|
201 "Socket closed");
202 return;
203 } else {
204 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
205 }
206
207 if (IS_NULL(iaObj)) {
208 JNU_ThrowNullPointerException(env, "iaObj is null.");
209 return;
210 }
211
212 /* bind */
213 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
214 return;
215 }
216 setDefaultScopeID(env, (struct sockaddr *)&him);
217
218 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
219 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
220 errno == EPERM || errno == EACCES) {
221 JNU_ThrowByNameWithLastError
222 (env, JNU_JAVANETPKG "BindException", "Bind failed");
223 } else {
224 JNU_ThrowByNameWithMessageAndLastError
225 (env, JNU_JAVANETPKG "SocketException", "Bind failed");
226 }
227 return;
228 }
229
230 /* initialize the local port */
231 if (localport == 0) {
232 /* Now that we're a connected socket, let's extract the port number
233 * that the system chose for us and store it in the Socket object.
234 */
235 if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) {
236 JNU_ThrowByNameWithMessageAndLastError
237 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
238 return;
239 }
240
241 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
242
243 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
244 } else {
245 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
246 }
247 }
248
249 /*
250 * Class: java_net_PlainDatagramSocketImpl
251 * Method: connect0
252 * Signature: (Ljava/net/InetAddress;I)V
253 */
254 JNIEXPORT void JNICALL
255 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
256 jobject address, jint port) {
257 /* The object's field */
264
265 if (IS_NULL(fdObj)) {
266 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
267 "Socket closed");
268 return;
269 }
270 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
271
272 if (IS_NULL(address)) {
273 JNU_ThrowNullPointerException(env, "address");
274 return;
275 }
276
277 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
278 return;
279 }
280
281 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
282
283 if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
284 JNU_ThrowByNameWithLastError
285 (env, JNU_JAVANETPKG "ConnectException", "Connect failed");
286 return;
287 }
288
289 }
290
291 /*
292 * Class: java_net_PlainDatagramSocketImpl
293 * Method: disconnect0
294 * Signature: ()V
295 */
296 JNIEXPORT void JNICALL
297 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
298 /* The object's field */
299 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
300 /* The fdObj'fd */
301 jint fd;
302
303 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
304 SOCKADDR addr;
305 socklen_t len;
452 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
453 }
454 #endif /* AF_INET6 */
455
456
457 /*
458 * Send the datagram.
459 *
460 * If we are connected it's possible that sendto will return
461 * ECONNREFUSED indicating that an ICMP port unreachable has
462 * received.
463 */
464 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
465 (struct sockaddr *)rmtaddrP, len);
466
467 if (ret < 0) {
468 if (errno == ECONNREFUSED) {
469 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
470 "ICMP Port Unreachable");
471 } else {
472 JNU_ThrowIOExceptionWithLastError(env, "sendto failed");
473 }
474 }
475
476 if (mallocedPacket) {
477 free(fullPacket);
478 }
479 return;
480 }
481
482 /*
483 * Class: java_net_PlainDatagramSocketImpl
484 * Method: peek
485 * Signature: (Ljava/net/InetAddress;)I
486 */
487 JNIEXPORT jint JNICALL
488 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
489 jobject addressObj) {
490
491 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
492 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
503 return -1;
504 } else {
505 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
506 }
507 if (IS_NULL(addressObj)) {
508 JNU_ThrowNullPointerException(env, "Null address in peek()");
509 return -1;
510 }
511 if (timeout) {
512 int ret = NET_Timeout(fd, timeout);
513 if (ret == 0) {
514 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
515 "Peek timed out");
516 return ret;
517 } else if (ret == -1) {
518 if (errno == EBADF) {
519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
520 } else if (errno == ENOMEM) {
521 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
522 } else {
523 JNU_ThrowByNameWithMessageAndLastError
524 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
525 }
526 return ret;
527 }
528 }
529
530 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);
531
532 if (n == -1) {
533
534 #ifdef __solaris__
535 if (errno == ECONNREFUSED) {
536 int orig_errno = errno;
537 (void) recv(fd, buf, 1, 0);
538 errno = orig_errno;
539 }
540 #endif
541 if (errno == ECONNREFUSED) {
542 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
543 "ICMP Port Unreachable");
544 } else {
545 if (errno == EBADF) {
546 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
547 } else {
548 JNU_ThrowByNameWithMessageAndLastError
549 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
550 }
551 }
552 return 0;
553 }
554
555 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
556 #ifdef AF_INET6
557 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
558 #else
559 family = AF_INET;
560 #endif
561 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
562 int address = getInetAddress_addr(env, iaObj);
563 setInetAddress_addr(env, addressObj, address);
564 }
565 return port;
566 }
567
568 JNIEXPORT jint JNICALL
569 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
601 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
602 if (IS_NULL(packetBuffer)) {
603 JNU_ThrowNullPointerException(env, "packet buffer");
604 return -1;
605 }
606 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
607 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
608 if (timeout) {
609 int ret = NET_Timeout(fd, timeout);
610 if (ret == 0) {
611 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
612 "Receive timed out");
613 return -1;
614 } else if (ret == -1) {
615 if (errno == ENOMEM) {
616 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
617 #ifdef __linux__
618 } else if (errno == EBADF) {
619 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
620 } else {
621 JNU_ThrowByNameWithMessageAndLastError
622 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
623 #else
624 } else {
625 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
626 #endif
627 }
628 return -1;
629 }
630 }
631
632 if (packetBufferLen > MAX_BUFFER_LEN) {
633
634 /* When JNI-ifying the JDK's IO routines, we turned
635 * reads and writes of byte arrays of size greater
636 * than 2048 bytes into several operations of size 2048.
637 * This saves a malloc()/memcpy()/free() for big
638 * buffers. This is OK for file IO and TCP, but that
639 * strategy violates the semantics of a datagram protocol.
640 * (one big send) != (several smaller sends). So here
641 * we *must* allocate the buffer. Note it needn't be bigger
642 * than 65,536 (0xFFFF), the max size of an IP packet.
667 n = packetBufferLen;
668 }
669 if (n == -1) {
670
671 #ifdef __solaris__
672 if (errno == ECONNREFUSED) {
673 int orig_errno = errno;
674 (void) recv(fd, fullPacket, 1, 0);
675 errno = orig_errno;
676 }
677 #endif
678 (*env)->SetIntField(env, packet, dp_offsetID, 0);
679 (*env)->SetIntField(env, packet, dp_lengthID, 0);
680 if (errno == ECONNREFUSED) {
681 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
682 "ICMP Port Unreachable");
683 } else {
684 if (errno == EBADF) {
685 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
686 } else {
687 JNU_ThrowByNameWithMessageAndLastError
688 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
689 }
690 }
691 } else {
692 /*
693 * success - fill in received address...
694 *
695 * REMIND: Fill in an int on the packet, and create inetadd
696 * object in Java, as a performance improvement. Also
697 * construct the inetadd object lazily.
698 */
699
700 jobject packetAddress;
701
702 /*
703 * Check if there is an InetAddress already associated with this
704 * packet. If so we check if it is the same source address. We
705 * can't update any existing InetAddress because it is immutable
706 */
707 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
708 if (packetAddress != NULL) {
814 } else {
815 fullPacket = &(BUF[0]);
816 }
817
818 do {
819 retry = JNI_FALSE;
820
821 if (timeout) {
822 int ret = NET_Timeout(fd, timeout);
823 if (ret <= 0) {
824 if (ret == 0) {
825 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
826 "Receive timed out");
827 } else if (ret == -1) {
828 if (errno == ENOMEM) {
829 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
830 #ifdef __linux__
831 } else if (errno == EBADF) {
832 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
833 } else {
834 JNU_ThrowByNameWithMessageAndLastError
835 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
836 #else
837 } else {
838 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
839 #endif
840 }
841 }
842
843 if (mallocedPacket) {
844 free(fullPacket);
845 }
846
847 return;
848 }
849 }
850
851 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
852 (struct sockaddr *)&remote_addr, &slen);
853 /* truncate the data if the packet's length is too small */
854 if (n > packetBufferLen) {
855 n = packetBufferLen;
856 }
857 if (n == -1) {
858 (*env)->SetIntField(env, packet, dp_offsetID, 0);
859 (*env)->SetIntField(env, packet, dp_lengthID, 0);
860 if (errno == ECONNREFUSED) {
861 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
862 "ICMP Port Unreachable");
863 } else {
864 if (errno == EBADF) {
865 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
866 } else {
867 JNU_ThrowByNameWithMessageAndLastError
868 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
869 }
870 }
871 } else {
872 int port;
873 jobject packetAddress;
874
875 /*
876 * success - fill in received address...
877 *
878 * REMIND: Fill in an int on the packet, and create inetadd
879 * object in Java, as a performance improvement. Also
880 * construct the inetadd object lazily.
881 */
882
883 /*
884 * Check if there is an InetAddress already associated with this
885 * packet. If so we check if it is the same source address. We
886 * can't update any existing InetAddress because it is immutable
887 */
888 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
921 */
922 JNIEXPORT void JNICALL
923 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
924 jobject this) {
925 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
926 int arg, fd, t = 1;
927 char tmpbuf[1024];
928 #ifdef AF_INET6
929 int domain = ipv6_available() ? AF_INET6 : AF_INET;
930 #else
931 int domain = AF_INET;
932 #endif
933
934 if (IS_NULL(fdObj)) {
935 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
936 "Socket closed");
937 return;
938 }
939
940 if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
941 JNU_ThrowByNameWithMessageAndLastError
942 (env, JNU_JAVANETPKG "SocketException", "Error creating socket");
943 return;
944 }
945
946 #ifdef AF_INET6
947 /* Disable IPV6_V6ONLY to ensure dual-socket support */
948 if (domain == AF_INET6) {
949 arg = 0;
950 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
951 sizeof(int)) < 0) {
952 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
953 close(fd);
954 return;
955 }
956 }
957 #endif /* AF_INET6 */
958
959 #ifdef __APPLE__
960 arg = 65507;
961 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
962 (char *)&arg, sizeof(arg)) < 0) {
1069 */
1070 if (len < 1) {
1071 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1072 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1073 return;
1074 }
1075
1076 /*
1077 * We need an ipv4 address here
1078 */
1079 for (i = 0; i < len; i++) {
1080 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1081 if (getInetAddress_family(env, addr) == IPv4) {
1082 in.s_addr = htonl(getInetAddress_addr(env, addr));
1083 break;
1084 }
1085 }
1086
1087 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1088 (const char*)&in, sizeof(in)) < 0) {
1089 JNU_ThrowByNameWithMessageAndLastError
1090 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1091 }
1092 }
1093
1094 /*
1095 * Set outgoing multicast interface designated by a NetworkInterface.
1096 * Throw exception if failed.
1097 */
1098 #ifdef AF_INET6
1099 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1100 static jfieldID ni_indexID;
1101 int index;
1102
1103 if (ni_indexID == NULL) {
1104 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1105 CHECK_NULL(c);
1106 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1107 CHECK_NULL(ni_indexID);
1108 }
1109 index = (*env)->GetIntField(env, value, ni_indexID);
1110
1111 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1112 (const char*)&index, sizeof(index)) < 0) {
1113 if (errno == EINVAL && index > 0) {
1114 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1115 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1116 "address only?)");
1117 } else {
1118 JNU_ThrowByNameWithMessageAndLastError
1119 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1120 }
1121 return;
1122 }
1123
1124 }
1125 #endif /* AF_INET6 */
1126
1127 /*
1128 * Set outgoing multicast interface designated by an InetAddress.
1129 * Throw exception if failed.
1130 */
1131 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1132 struct in_addr in;
1133
1134 in.s_addr = htonl( getInetAddress_addr(env, value) );
1135
1136 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1137 (const char*)&in, sizeof(in)) < 0) {
1138 JNU_ThrowByNameWithMessageAndLastError
1139 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1140 }
1141 }
1142
1143 /*
1144 * Set outgoing multicast interface designated by an InetAddress.
1145 * Throw exception if failed.
1146 */
1147 #ifdef AF_INET6
1148 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1149 static jclass ni_class;
1150 if (ni_class == NULL) {
1151 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1152 CHECK_NULL(c);
1153 ni_class = (*env)->NewGlobalRef(env, c);
1154 CHECK_NULL(ni_class);
1155 }
1156
1157 value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1158 if (value == NULL) {
1159 if (!(*env)->ExceptionOccurred(env)) {
1245 }
1246 }
1247
1248 /*
1249 * Enable/disable local loopback of multicast datagrams.
1250 */
1251 static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1252 jclass cls;
1253 jfieldID fid;
1254 jboolean on;
1255 char loopback;
1256
1257 cls = (*env)->FindClass(env, "java/lang/Boolean");
1258 CHECK_NULL(cls);
1259 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1260 CHECK_NULL(fid);
1261
1262 on = (*env)->GetBooleanField(env, value, fid);
1263 loopback = (!on ? 1 : 0);
1264
1265 if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
1266 (const void *)&loopback, sizeof(char)) < 0) {
1267 JNU_ThrowByNameWithMessageAndLastError
1268 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1269 return;
1270 }
1271 }
1272
1273 /*
1274 * Enable/disable local loopback of multicast datagrams.
1275 */
1276 #ifdef AF_INET6
1277 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1278 jclass cls;
1279 jfieldID fid;
1280 jboolean on;
1281 int loopback;
1282
1283 cls = (*env)->FindClass(env, "java/lang/Boolean");
1284 CHECK_NULL(cls);
1285 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1286 CHECK_NULL(fid);
1287
1288 on = (*env)->GetBooleanField(env, value, fid);
1289 loopback = (!on ? 1 : 0);
1290
1291 if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
1292 (const void *)&loopback, sizeof(int)) < 0) {
1293 JNU_ThrowByNameWithMessageAndLastError
1294 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1295 return;
1296 }
1297
1298 }
1299 #endif /* AF_INET6 */
1300
1301 /*
1302 * Sets the multicast loopback mode.
1303 */
1304 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
1305 jint opt, jobject value) {
1306 #ifdef AF_INET6
1307 #ifdef __linux__
1308 mcast_set_loop_v4(env, this, fd, value);
1309 if (ipv6_available()) {
1310 if ((*env)->ExceptionCheck(env)){
1311 (*env)->ExceptionClear(env);
1312 }
1313 mcast_set_loop_v6(env, this, fd, value);
1314 }
1413 CHECK_NULL(cls);
1414 fid = (*env)->GetFieldID(env, cls, "value", "Z");
1415 CHECK_NULL(fid);
1416
1417 on = (*env)->GetBooleanField(env, value, fid);
1418
1419 /* SO_REUSEADDR or SO_BROADCAST */
1420 optval = (on ? 1 : 0);
1421
1422 break;
1423 }
1424
1425 default :
1426 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1427 "Socket option not supported by PlainDatagramSocketImp");
1428 return;
1429
1430 }
1431
1432 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
1433 JNU_ThrowByNameWithMessageAndLastError
1434 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1435 return;
1436 }
1437 }
1438
1439
1440 /*
1441 * Return the multicast interface:
1442 *
1443 * SocketOptions.IP_MULTICAST_IF
1444 * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
1445 * Create InetAddress
1446 * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1447 * kernel but struct in_addr on 2.4 kernel
1448 * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1449 * If index == 0 return InetAddress representing
1450 * anyLocalAddress.
1451 * If index > 0 query NetworkInterface by index
1452 * and returns addrs[0]
1453 *
1454 * SocketOptions.IP_MULTICAST_IF2
1477 static jclass inet4_class;
1478 static jmethodID inet4_ctrID;
1479
1480 static jclass ni_class;
1481 static jmethodID ni_ctrID;
1482 static jfieldID ni_indexID;
1483 static jfieldID ni_addrsID;
1484 static jfieldID ni_nameID;
1485
1486 jobjectArray addrArray;
1487 jobject addr;
1488 jobject ni;
1489 jobject ni_name;
1490
1491 struct in_addr in;
1492 struct in_addr *inP = ∈
1493 socklen_t len = sizeof(struct in_addr);
1494
1495 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1496 (char *)inP, &len) < 0) {
1497 JNU_ThrowByNameWithMessageAndLastError
1498 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1499 return NULL;
1500 }
1501
1502 /*
1503 * Construct and populate an Inet4Address
1504 */
1505 if (inet4_class == NULL) {
1506 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1507 CHECK_NULL_RETURN(c, NULL);
1508 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1509 CHECK_NULL_RETURN(inet4_ctrID, NULL);
1510 inet4_class = (*env)->NewGlobalRef(env, c);
1511 CHECK_NULL_RETURN(inet4_class, NULL);
1512 }
1513 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1514 CHECK_NULL_RETURN(addr, NULL);
1515
1516 setInetAddress_addr(env, addr, ntohl(in.s_addr));
1517
1518 /*
1575 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1576
1577 static jclass ni_class;
1578 static jmethodID ni_ctrID;
1579 static jfieldID ni_indexID;
1580 static jfieldID ni_addrsID;
1581 static jclass ia_class;
1582 static jfieldID ni_nameID;
1583 static jmethodID ia_anyLocalAddressID;
1584
1585 int index = 0;
1586 socklen_t len = sizeof(index);
1587
1588 jobjectArray addrArray;
1589 jobject addr;
1590 jobject ni;
1591 jobject ni_name;
1592
1593 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1594 (char*)&index, &len) < 0) {
1595 JNU_ThrowByNameWithMessageAndLastError
1596 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1597 return NULL;
1598 }
1599
1600 if (ni_class == NULL) {
1601 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1602 CHECK_NULL_RETURN(c, NULL);
1603 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1604 CHECK_NULL_RETURN(ni_ctrID, NULL);
1605 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1606 CHECK_NULL_RETURN(ni_indexID, NULL);
1607 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1608 "[Ljava/net/InetAddress;");
1609 CHECK_NULL_RETURN(ni_addrsID, NULL);
1610
1611 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1612 CHECK_NULL_RETURN(ia_class, NULL);
1613 ia_class = (*env)->NewGlobalRef(env, ia_class);
1614 CHECK_NULL_RETURN(ia_class, NULL);
1615 ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1616 ia_class,
1720 */
1721 if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1722 opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1723 return getMulticastInterface(env, this, fd, opt);
1724
1725 }
1726
1727 /*
1728 * SO_BINDADDR implemented using getsockname
1729 */
1730 if (opt == java_net_SocketOptions_SO_BINDADDR) {
1731 /* find out local IP address */
1732 SOCKADDR him;
1733 socklen_t len = 0;
1734 int port;
1735 jobject iaObj;
1736
1737 len = SOCKADDR_LEN;
1738
1739 if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
1740 JNU_ThrowByNameWithMessageAndLastError
1741 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
1742 return NULL;
1743 }
1744 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1745
1746 return iaObj;
1747 }
1748
1749 /*
1750 * Map the Java level socket option to the platform specific
1751 * level and option name.
1752 */
1753 if (NET_MapSocketOption(opt, &level, &optname)) {
1754 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1755 return NULL;
1756 }
1757
1758 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&
1759 level == IPPROTO_IP) {
1760 optlen = sizeof(optval.c);
1761 } else {
1762 optlen = sizeof(optval.i);
1763 }
1764
1765 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1766 JNU_ThrowByNameWithMessageAndLastError
1767 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1768 return NULL;
1769 }
1770
1771 switch (opt) {
1772 case java_net_SocketOptions_IP_MULTICAST_LOOP:
1773 /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */
1774 if (level == IPPROTO_IP) {
1775 return createBoolean(env, (int)!optval.c);
1776 } else {
1777 return createBoolean(env, !optval.i);
1778 }
1779
1780 case java_net_SocketOptions_SO_BROADCAST:
1781 case java_net_SocketOptions_SO_REUSEADDR:
1782 return createBoolean(env, optval.i);
1783
1784 case java_net_SocketOptions_SO_REUSEPORT:
1785 return createBoolean(env, optval.i);
1786
1787 case java_net_SocketOptions_SO_SNDBUF:
1799 * Multicast-related calls
1800 */
1801
1802 JNIEXPORT void JNICALL
1803 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1804 jbyte ttl) {
1805 jint ittl = ttl;
1806 if (ittl < 0) {
1807 ittl += 0x100;
1808 }
1809 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1810 }
1811
1812 /*
1813 * Set TTL for a socket. Throw exception if failed.
1814 */
1815 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1816 char ittl = (char)ttl;
1817 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1818 sizeof(ittl)) < 0) {
1819 JNU_ThrowByNameWithMessageAndLastError
1820 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1821 }
1822 }
1823
1824 /*
1825 * Set hops limit for a socket. Throw exception if failed.
1826 */
1827 #ifdef AF_INET6
1828 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1829 int ittl = (int)ttl;
1830 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1831 (char*)&ittl, sizeof(ittl)) < 0) {
1832 JNU_ThrowByNameWithMessageAndLastError
1833 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1834 }
1835 }
1836 #endif
1837
1838 /*
1839 * Class: java_net_PlainDatagramSocketImpl
1840 * Method: setTTL
1841 * Signature: (B)V
1842 */
1843 JNIEXPORT void JNICALL
1844 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1845 jint ttl) {
1846
1847 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1848 int fd;
1849 /* it is important to cast this to a char, otherwise setsockopt gets confused */
1850
1851 if (IS_NULL(fdObj)) {
1852 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1853 "Socket closed");
1895 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1896
1897 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1898 jint fd = -1;
1899
1900 if (IS_NULL(fdObj)) {
1901 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1902 "Socket closed");
1903 return -1;
1904 } else {
1905 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1906 }
1907 /* getsockopt of TTL */
1908 #ifdef AF_INET6
1909 if (ipv6_available()) {
1910 int ttl = 0;
1911 socklen_t len = sizeof(ttl);
1912
1913 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1914 (char*)&ttl, &len) < 0) {
1915 JNU_ThrowByNameWithMessageAndLastError
1916 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1917 return -1;
1918 }
1919 return (jint)ttl;
1920 } else
1921 #endif /* AF_INET6 */
1922 {
1923 u_char ttl = 0;
1924 socklen_t len = sizeof(ttl);
1925 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1926 (char*)&ttl, &len) < 0) {
1927 JNU_ThrowByNameWithMessageAndLastError
1928 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1929 return -1;
1930 }
1931 return (jint)ttl;
1932 }
1933 }
1934
1935
1936 /*
1937 * mcast_join_leave: Join or leave a multicast group.
1938 *
1939 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1940 * to join/leave multicast group.
1941 *
1942 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1943 * to join/leave multicast group. If multicast group is an IPv4 address then
1944 * an IPv4-mapped address is used.
1945 *
1946 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1947 * we must use the IPv4 socket options. This is because the IPv6 socket options
1948 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
|