169 initInetAddressIDs(env);
170 JNU_CHECK_EXCEPTION(env);
171 Java_java_net_NetworkInterface_init(env, 0);
172
173 }
174
175 /*
176 * Class: java_net_PlainDatagramSocketImpl
177 * Method: bind
178 * Signature: (ILjava/net/InetAddress;)V
179 */
180 JNIEXPORT void JNICALL
181 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
182 jint localport, jobject iaObj) {
183 /* fdObj is the FileDescriptor field on this */
184 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
185 /* fd is an int field on fdObj */
186 int fd;
187 int len = 0;
188 SOCKADDR him;
189
190 if (IS_NULL(fdObj)) {
191 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
192 "Socket closed");
193 return;
194 } else {
195 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
196 }
197
198 if (IS_NULL(iaObj)) {
199 JNU_ThrowNullPointerException(env, "iaObj is null.");
200 return;
201 }
202
203 /* bind */
204 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
205 return;
206 }
207 setDefaultScopeID(env, (struct sockaddr *)&him);
208
209 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
210 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
211 errno == EPERM || errno == EACCES) {
212 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
213 "Bind failed");
214 } else {
215 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
216 "Bind failed");
217 }
218 return;
219 }
220
221 /* initialize the local port */
222 if (localport == 0) {
223 /* Now that we're a connected socket, let's extract the port number
224 * that the system chose for us and store it in the Socket object.
225 */
226 if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
227 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
228 "Error getting socket name");
229 return;
230 }
231
232 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
233
234 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
235 } else {
236 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
237 }
238 }
239
240 /*
241 * Class: java_net_PlainDatagramSocketImpl
242 * Method: connect0
243 * Signature: (Ljava/net/InetAddress;I)V
244 */
245 JNIEXPORT void JNICALL
246 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
254 int len = 0;
255
256 if (IS_NULL(fdObj)) {
257 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
258 "Socket closed");
259 return;
260 }
261 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
262
263 if (IS_NULL(address)) {
264 JNU_ThrowNullPointerException(env, "address");
265 return;
266 }
267
268 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
269 return;
270 }
271
272 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
273
274 if (JVM_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
275 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
276 "Connect failed");
277 return;
278 }
279
280 }
281
282 /*
283 * Class: java_net_PlainDatagramSocketImpl
284 * Method: disconnect0
285 * Signature: ()V
286 */
287 JNIEXPORT void JNICALL
288 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
289 /* The object's field */
290 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
291 /* The fdObj'fd */
292 jint fd;
293
294 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
295 SOCKADDR addr;
296 int len;
297 #endif
298
299 if (IS_NULL(fdObj)) {
300 return;
301 }
302 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
303
304 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
305 memset(&addr, 0, sizeof(addr));
306 #ifdef AF_INET6
307 if (ipv6_available()) {
308 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
309 him6->sin6_family = AF_UNSPEC;
310 len = sizeof(struct sockaddr_in6);
311 } else
312 #endif
313 {
314 struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
315 him4->sin_family = AF_UNSPEC;
316 len = sizeof(struct sockaddr_in);
317 }
318 JVM_Connect(fd, (struct sockaddr *)&addr, len);
319
320 #ifdef __linux__
321 int localPort = 0;
322 if (JVM_GetSockName(fd, (struct sockaddr *)&addr, &len) == -1)
323 return;
324
325 localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
326 if (localPort == 0) {
327 localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
328 #ifdef AF_INET6
329 if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
330 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
331 } else
332 #endif /* AF_INET6 */
333 {
334 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
335 }
336
337 NET_Bind(fd, (struct sockaddr *)&addr, len);
338 }
339
340 #endif
341 #else
342 JVM_Connect(fd, 0, 0);
343 #endif
344 }
345
346 /*
347 * Class: java_net_PlainDatagramSocketImpl
348 * Method: send
349 * Signature: (Ljava/net/DatagramPacket;)V
350 */
351 JNIEXPORT void JNICALL
352 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
353 jobject packet) {
354
355 char BUF[MAX_BUFFER_LEN];
356 char *fullPacket = NULL;
357 int ret, mallocedPacket = JNI_FALSE;
358 /* The object's field */
359 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
360 jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
361
362 jbyteArray packetBuffer;
439 (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
440 (jbyte *)fullPacket);
441 #ifdef AF_INET6
442 if (trafficClass != 0 && ipv6_available()) {
443 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
444 }
445 #endif /* AF_INET6 */
446
447
448 /*
449 * Send the datagram.
450 *
451 * If we are connected it's possible that sendto will return
452 * ECONNREFUSED indicating that an ICMP port unreachable has
453 * received.
454 */
455 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
456 (struct sockaddr *)rmtaddrP, len);
457
458 if (ret < 0) {
459 switch (ret) {
460 case JVM_IO_ERR :
461 if (errno == ECONNREFUSED) {
462 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
463 "ICMP Port Unreachable");
464 } else {
465 NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
466 }
467 break;
468
469 case JVM_IO_INTR:
470 JNU_ThrowByName(env, "java/io/InterruptedIOException",
471 "operation interrupted");
472 break;
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);
493 jint fd;
494 ssize_t n;
495 SOCKADDR remote_addr;
496 int len;
497 char buf[1];
498 jint family;
499 jobject iaObj;
500 int port;
501 if (IS_NULL(fdObj)) {
502 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
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 == JVM_IO_ERR) {
518 if (errno == EBADF) {
519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
520 } else {
521 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
522 }
523 return ret;
524 } else if (ret == JVM_IO_INTR) {
525 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
526 "operation interrupted");
527 return ret; /* WARNING: SHOULD WE REALLY RETURN -2??? */
528 }
529 }
530
531 len = SOCKADDR_LEN;
532 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK,
533 (struct sockaddr *)&remote_addr, &len);
534
535 if (n == JVM_IO_ERR) {
536
537 #ifdef __solaris__
538 if (errno == ECONNREFUSED) {
539 int orig_errno = errno;
540 (void) recv(fd, buf, 1, 0);
541 errno = orig_errno;
542 }
543 #endif
544 if (errno == ECONNREFUSED) {
545 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
546 "ICMP Port Unreachable");
547 } else {
548 if (errno == EBADF) {
549 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
550 } else {
551 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
552 }
553 }
554 return 0;
555 } else if (n == JVM_IO_INTR) {
556 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
557 return 0;
558 }
559
560 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
561 #ifdef AF_INET6
562 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
563 #else
564 family = AF_INET;
565 #endif
566 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
567 int address = getInetAddress_addr(env, iaObj);
568 setInetAddress_addr(env, addressObj, address);
569 }
570 return port;
571 }
572
573 JNIEXPORT jint JNICALL
574 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
575 jobject packet) {
576
577 char BUF[MAX_BUFFER_LEN];
578 char *fullPacket = NULL;
579 int mallocedPacket = JNI_FALSE;
580 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
581 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
582
583 jbyteArray packetBuffer;
584 jint packetBufferOffset, packetBufferLen;
585
586 int fd;
587
588 int n;
589 SOCKADDR remote_addr;
590 int len;
591 int port;
592
593 if (IS_NULL(fdObj)) {
594 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
595 "Socket closed");
596 return -1;
597 }
598
599 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
600
601 if (IS_NULL(packet)) {
602 JNU_ThrowNullPointerException(env, "packet");
603 return -1;
604 }
605
606 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
607 if (IS_NULL(packetBuffer)) {
608 JNU_ThrowNullPointerException(env, "packet buffer");
609 return -1;
610 }
611 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
612 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
613 if (timeout) {
614 int ret = NET_Timeout(fd, timeout);
615 if (ret == 0) {
616 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
617 "Receive timed out");
618 return -1;
619 } else if (ret == JVM_IO_ERR) {
620 #ifdef __linux__
621 if (errno == EBADF) {
622 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
623 } else {
624 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
625 }
626 #else
627 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
628 #endif
629 return -1;
630 } else if (ret == JVM_IO_INTR) {
631 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
632 "operation interrupted");
633 return -1;
634 }
635 }
636
637 if (packetBufferLen > MAX_BUFFER_LEN) {
638
639 /* When JNI-ifying the JDK's IO routines, we turned
640 * reads and writes of byte arrays of size greater
641 * than 2048 bytes into several operations of size 2048.
642 * This saves a malloc()/memcpy()/free() for big
643 * buffers. This is OK for file IO and TCP, but that
644 * strategy violates the semantics of a datagram protocol.
645 * (one big send) != (several smaller sends). So here
646 * we *must* allocate the buffer. Note it needn't be bigger
647 * than 65,536 (0xFFFF), the max size of an IP packet.
648 * anything bigger is truncated anyway.
649 *
650 * We may want to use a smarter allocation scheme at some
651 * point.
652 */
653 if (packetBufferLen > MAX_PACKET_LEN) {
654 packetBufferLen = MAX_PACKET_LEN;
655 }
656 fullPacket = (char *)malloc(packetBufferLen);
657
658 if (!fullPacket) {
659 JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
660 return -1;
661 } else {
662 mallocedPacket = JNI_TRUE;
663 }
664 } else {
665 fullPacket = &(BUF[0]);
666 }
667
668 len = SOCKADDR_LEN;
669 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
670 (struct sockaddr *)&remote_addr, &len);
671 /* truncate the data if the packet's length is too small */
672 if (n > packetBufferLen) {
673 n = packetBufferLen;
674 }
675 if (n == JVM_IO_ERR) {
676
677 #ifdef __solaris__
678 if (errno == ECONNREFUSED) {
679 int orig_errno = errno;
680 (void) recv(fd, fullPacket, 1, 0);
681 errno = orig_errno;
682 }
683 #endif
684 (*env)->SetIntField(env, packet, dp_offsetID, 0);
685 (*env)->SetIntField(env, packet, dp_lengthID, 0);
686 if (errno == ECONNREFUSED) {
687 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
688 "ICMP Port Unreachable");
689 } else {
690 if (errno == EBADF) {
691 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
692 } else {
693 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
694 }
695 }
696 } else if (n == JVM_IO_INTR) {
697 (*env)->SetIntField(env, packet, dp_offsetID, 0);
698 (*env)->SetIntField(env, packet, dp_lengthID, 0);
699 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
700 "operation interrupted");
701 } else {
702 /*
703 * success - fill in received address...
704 *
705 * REMIND: Fill in an int on the packet, and create inetadd
706 * object in Java, as a performance improvement. Also
707 * construct the inetadd object lazily.
708 */
709
710 jobject packetAddress;
711
712 /*
713 * Check if there is an InetAddress already associated with this
714 * packet. If so we check if it is the same source address. We
715 * can't update any existing InetAddress because it is immutable
716 */
717 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
718 if (packetAddress != NULL) {
719 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
720 /* force a new InetAddress to be created */
747 * Method: receive
748 * Signature: (Ljava/net/DatagramPacket;)V
749 */
750 JNIEXPORT void JNICALL
751 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
752 jobject packet) {
753
754 char BUF[MAX_BUFFER_LEN];
755 char *fullPacket = NULL;
756 int mallocedPacket = JNI_FALSE;
757 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
758 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
759
760 jbyteArray packetBuffer;
761 jint packetBufferOffset, packetBufferLen;
762
763 int fd;
764
765 int n;
766 SOCKADDR remote_addr;
767 int len;
768 jboolean retry;
769 #ifdef __linux__
770 jboolean connected = JNI_FALSE;
771 jobject connectedAddress = NULL;
772 jint connectedPort = 0;
773 jlong prevTime = 0;
774 #endif
775
776 if (IS_NULL(fdObj)) {
777 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
778 "Socket closed");
779 return;
780 }
781
782 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
783
784 if (IS_NULL(packet)) {
785 JNU_ThrowNullPointerException(env, "packet");
786 return;
787 }
817
818 if (!fullPacket) {
819 JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
820 return;
821 } else {
822 mallocedPacket = JNI_TRUE;
823 }
824 } else {
825 fullPacket = &(BUF[0]);
826 }
827
828 do {
829 retry = JNI_FALSE;
830
831 if (timeout) {
832 int ret = NET_Timeout(fd, timeout);
833 if (ret <= 0) {
834 if (ret == 0) {
835 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
836 "Receive timed out");
837 } else if (ret == JVM_IO_ERR) {
838 #ifdef __linux__
839 if (errno == EBADF) {
840 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
841 } else {
842 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
843 }
844 #else
845 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
846 #endif
847 } else if (ret == JVM_IO_INTR) {
848 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
849 "operation interrupted");
850 }
851
852 if (mallocedPacket) {
853 free(fullPacket);
854 }
855
856 return;
857 }
858 }
859
860 len = SOCKADDR_LEN;
861 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
862 (struct sockaddr *)&remote_addr, &len);
863 /* truncate the data if the packet's length is too small */
864 if (n > packetBufferLen) {
865 n = packetBufferLen;
866 }
867 if (n == JVM_IO_ERR) {
868 (*env)->SetIntField(env, packet, dp_offsetID, 0);
869 (*env)->SetIntField(env, packet, dp_lengthID, 0);
870 if (errno == ECONNREFUSED) {
871 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
872 "ICMP Port Unreachable");
873 } else {
874 if (errno == EBADF) {
875 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
876 } else {
877 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
878 }
879 }
880 } else if (n == JVM_IO_INTR) {
881 (*env)->SetIntField(env, packet, dp_offsetID, 0);
882 (*env)->SetIntField(env, packet, dp_lengthID, 0);
883 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
884 "operation interrupted");
885 } else {
886 int port;
887 jobject packetAddress;
888
889 /*
890 * success - fill in received address...
891 *
892 * REMIND: Fill in an int on the packet, and create inetadd
893 * object in Java, as a performance improvement. Also
894 * construct the inetadd object lazily.
895 */
896
897 /*
898 * Check if there is an InetAddress already associated with this
899 * packet. If so we check if it is the same source address. We
900 * can't update any existing InetAddress because it is immutable
901 */
902 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
903 if (packetAddress != NULL) {
904 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
933 * Method: datagramSocketCreate
934 * Signature: ()V
935 */
936 JNIEXPORT void JNICALL
937 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
938 jobject this) {
939 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
940 int arg, fd, t = 1;
941 #ifdef AF_INET6
942 int domain = ipv6_available() ? AF_INET6 : AF_INET;
943 #else
944 int domain = AF_INET;
945 #endif
946
947 if (IS_NULL(fdObj)) {
948 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
949 "Socket closed");
950 return;
951 }
952
953 if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
954 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
955 "Error creating socket");
956 return;
957 }
958
959 #ifdef AF_INET6
960 /* Disable IPV6_V6ONLY to ensure dual-socket support */
961 if (domain == AF_INET6) {
962 arg = 0;
963 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
964 sizeof(int)) < 0) {
965 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
966 close(fd);
967 return;
968 }
969 }
970 #endif /* AF_INET6 */
971
972 #ifdef __APPLE__
973 arg = 65507;
974 if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF,
975 (char *)&arg, sizeof(arg)) < 0) {
976 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
977 strerror(errno));
978 return;
979 }
980 if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF,
981 (char *)&arg, sizeof(arg)) < 0) {
982 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
983 strerror(errno));
984 return;
985 }
986 #endif /* __APPLE__ */
987
988 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
989
990 #if defined(__linux__)
991 arg = 0;
992 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
993 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
994 (errno != ENOPROTOOPT)) {
995 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
996 strerror(errno));
997 close(fd);
998 return;
999 }
1000 #endif
1067 * Check that there is at least one address bound to this
1068 * interface.
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 (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1088 (const char*)&in, sizeof(in)) < 0) {
1089 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1090 "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 (JVM_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 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1119 "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 (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1137 (const char*)&in, sizeof(in)) < 0) {
1138 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1139 "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
1465 #endif
1466
1467 /*
1468 * IPv4 implementation
1469 */
1470 if (isIPV4) {
1471 static jclass inet4_class;
1472 static jmethodID inet4_ctrID;
1473
1474 static jclass ni_class;
1475 static jmethodID ni_ctrID;
1476 static jfieldID ni_indexID;
1477 static jfieldID ni_addrsID;
1478
1479 jobjectArray addrArray;
1480 jobject addr;
1481 jobject ni;
1482
1483 struct in_addr in;
1484 struct in_addr *inP = ∈
1485 int len = sizeof(struct in_addr);
1486
1487 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1488 (char *)inP, &len) < 0) {
1489 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1490 "Error getting socket option");
1491 return NULL;
1492 }
1493
1494 /*
1495 * Construct and populate an Inet4Address
1496 */
1497 if (inet4_class == NULL) {
1498 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1499 CHECK_NULL_RETURN(c, NULL);
1500 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1501 CHECK_NULL_RETURN(inet4_ctrID, NULL);
1502 inet4_class = (*env)->NewGlobalRef(env, c);
1503 CHECK_NULL_RETURN(inet4_class, NULL);
1504 }
1505 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1506 CHECK_NULL_RETURN(addr, NULL);
1507
1551 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1552 return ni;
1553 }
1554
1555
1556 #ifdef AF_INET6
1557 /*
1558 * IPv6 implementation
1559 */
1560 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1561 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1562
1563 static jclass ni_class;
1564 static jmethodID ni_ctrID;
1565 static jfieldID ni_indexID;
1566 static jfieldID ni_addrsID;
1567 static jclass ia_class;
1568 static jmethodID ia_anyLocalAddressID;
1569
1570 int index;
1571 int len = sizeof(index);
1572
1573 jobjectArray addrArray;
1574 jobject addr;
1575 jobject ni;
1576
1577 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1578 (char*)&index, &len) < 0) {
1579 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1580 "Error getting socket option");
1581 return NULL;
1582 }
1583
1584 if (ni_class == NULL) {
1585 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1586 CHECK_NULL_RETURN(c, NULL);
1587 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1588 CHECK_NULL_RETURN(ni_ctrID, NULL);
1589 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1590 CHECK_NULL_RETURN(ni_indexID, NULL);
1591 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1592 "[Ljava/net/InetAddress;");
1593 CHECK_NULL_RETURN(ni_addrsID, NULL);
1594
1595 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1596 CHECK_NULL_RETURN(ia_class, NULL);
1597 ia_class = (*env)->NewGlobalRef(env, ia_class);
1772
1773 /*
1774 * Multicast-related calls
1775 */
1776
1777 JNIEXPORT void JNICALL
1778 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1779 jbyte ttl) {
1780 jint ittl = ttl;
1781 if (ittl < 0) {
1782 ittl += 0x100;
1783 }
1784 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1785 }
1786
1787 /*
1788 * Set TTL for a socket. Throw exception if failed.
1789 */
1790 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1791 char ittl = (char)ttl;
1792 if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1793 sizeof(ittl)) < 0) {
1794 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1795 "Error setting socket option");
1796 }
1797 }
1798
1799 /*
1800 * Set hops limit for a socket. Throw exception if failed.
1801 */
1802 #ifdef AF_INET6
1803 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1804 int ittl = (int)ttl;
1805 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1806 (char*)&ittl, sizeof(ittl)) < 0) {
1807 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1808 "Error setting socket option");
1809 }
1810 }
1811 #endif
1812
1813 /*
1814 * Class: java_net_PlainDatagramSocketImpl
1815 * Method: setTTL
1816 * Signature: (B)V
1817 */
1818 JNIEXPORT void JNICALL
1819 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1820 jint ttl) {
1821
1822 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1823 int fd;
1824 /* it is important to cast this to a char, otherwise setsockopt gets confused */
1825
1866 * Method: getTTL
1867 * Signature: ()B
1868 */
1869 JNIEXPORT jint JNICALL
1870 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1871
1872 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1873 jint fd = -1;
1874
1875 if (IS_NULL(fdObj)) {
1876 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1877 "Socket closed");
1878 return -1;
1879 } else {
1880 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1881 }
1882 /* getsockopt of TTL */
1883 #ifdef AF_INET6
1884 if (ipv6_available()) {
1885 int ttl = 0;
1886 int len = sizeof(ttl);
1887
1888 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1889 (char*)&ttl, &len) < 0) {
1890 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1891 "Error getting socket option");
1892 return -1;
1893 }
1894 return (jint)ttl;
1895 } else
1896 #endif /* AF_INET6 */
1897 {
1898 u_char ttl = 0;
1899 int len = sizeof(ttl);
1900 if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1901 (char*)&ttl, &len) < 0) {
1902 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1903 "Error getting socket option");
1904 return -1;
1905 }
1906 return (jint)ttl;
1907 }
1908 }
1909
1910
1911 /*
1912 * mcast_join_leave: Join or leave a multicast group.
1913 *
1914 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1915 * to join/leave multicast group.
1916 *
1917 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1918 * to join/leave multicast group. If multicast group is an IPv4 address then
1919 * an IPv4-mapped address is used.
1920 *
2033 /*
2034 * joinGroup(InetAddress) implementation :-
2035 *
2036 * Linux/IPv6: use ip_mreqn structure populated with multicast
2037 * address and interface index. index obtained
2038 * from cached value or IPV6_MULTICAST_IF.
2039 *
2040 * IPv4: use ip_mreq structure populated with multicast
2041 * address and local address obtained from
2042 * IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
2043 * returns different structure depending on
2044 * kernel.
2045 */
2046
2047 if (niObj == NULL) {
2048
2049 #if defined(__linux__) && defined(AF_INET6)
2050 if (ipv6_available()) {
2051
2052 int index;
2053 int len = sizeof(index);
2054
2055 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2056 (char*)&index, &len) < 0) {
2057 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2058 return;
2059 }
2060
2061 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2062 mname.imr_address.s_addr = 0 ;
2063 mname.imr_ifindex = index;
2064 mname_len = sizeof(struct ip_mreqn);
2065 } else
2066 #endif
2067 {
2068 struct in_addr in;
2069 struct in_addr *inP = ∈
2070 socklen_t len = sizeof(struct in_addr);
2071
2072 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) {
2073 NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed");
2074 return;
2075 }
2076
2077 #ifdef __linux__
2078 mname.imr_address.s_addr = in.s_addr;
2079
2080 #else
2081 mname.imr_interface.s_addr = in.s_addr;
2082 #endif
2083 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2084 mname_len = sizeof(struct ip_mreq);
2085 }
2086 }
2087
2088
2089 /*
2090 * Join the multicast group.
2091 */
2092 if (JVM_SetSockOpt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
2093 (char *) &mname, mname_len) < 0) {
2094
2095 /*
2096 * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
2097 * IPv6 enabled then it's possible that the kernel has been fixed
2098 * so we switch to IPV6_ADD_MEMBERSHIP socket option.
2099 * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped
2100 * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast
2101 * groups. However if the socket is an IPv6 socket then then setsockopt
2102 * should return ENOPROTOOPT. We assume this will be fixed in Linux
2103 * at some stage.
2104 */
2105 #if defined(__linux__) && defined(AF_INET6)
2106 if (errno == ENOPROTOOPT) {
2107 if (ipv6_available()) {
2108 ipv6_join_leave = JNI_TRUE;
2109 errno = 0;
2110 } else {
2111 errno = ENOPROTOOPT; /* errno can be changed by ipv6_available */
2112 }
2148 jint address;
2149 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
2150 if (family == AF_INET) { /* will convert to IPv4-mapped address */
2151 memset((char *) caddr, 0, 16);
2152 address = getInetAddress_addr(env, iaObj);
2153
2154 caddr[10] = 0xff;
2155 caddr[11] = 0xff;
2156
2157 caddr[12] = ((address >> 24) & 0xff);
2158 caddr[13] = ((address >> 16) & 0xff);
2159 caddr[14] = ((address >> 8) & 0xff);
2160 caddr[15] = (address & 0xff);
2161 } else {
2162 getInet6Address_ipaddress(env, iaObj, (char*)caddr);
2163 }
2164
2165 memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
2166 if (IS_NULL(niObj)) {
2167 int index;
2168 int len = sizeof(index);
2169
2170 if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2171 (char*)&index, &len) < 0) {
2172 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2173 return;
2174 }
2175
2176 #ifdef __linux__
2177 /*
2178 * On 2.4.8+ if we join a group with the interface set to 0
2179 * then the kernel records the interface it decides. This causes
2180 * subsequent leave groups to fail as there is no match. Thus we
2181 * pick the interface if there is a matching route.
2182 */
2183 if (index == 0) {
2184 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr));
2185 if (rt_index > 0) {
2186 index = rt_index;
2187 }
2188 }
2189 #endif
2190 #ifdef MACOSX
2194 #endif
2195 mname6.ipv6mr_interface = index;
2196 } else {
2197 jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
2198 mname6.ipv6mr_interface = idx;
2199 }
2200
2201 #if defined(_ALLBSD_SOURCE)
2202 #define ADD_MEMBERSHIP IPV6_JOIN_GROUP
2203 #define DRP_MEMBERSHIP IPV6_LEAVE_GROUP
2204 #define S_ADD_MEMBERSHIP "IPV6_JOIN_GROUP"
2205 #define S_DRP_MEMBERSHIP "IPV6_LEAVE_GROUP"
2206 #else
2207 #define ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
2208 #define DRP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
2209 #define S_ADD_MEMBERSHIP "IPV6_ADD_MEMBERSHIP"
2210 #define S_DRP_MEMBERSHIP "IPV6_DROP_MEMBERSHIP"
2211 #endif
2212
2213 /* Join the multicast group */
2214 if (JVM_SetSockOpt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
2215 (char *) &mname6, sizeof (mname6)) < 0) {
2216
2217 if (join) {
2218 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
2219 } else {
2220 if (errno == ENOENT) {
2221 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2222 "Not a member of the multicast group");
2223 } else {
2224 NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
2225 }
2226 }
2227 }
2228 }
2229 #endif
2230 }
2231
2232 /*
2233 * Class: java_net_PlainDatagramSocketImpl
2234 * Method: join
|
169 initInetAddressIDs(env);
170 JNU_CHECK_EXCEPTION(env);
171 Java_java_net_NetworkInterface_init(env, 0);
172
173 }
174
175 /*
176 * Class: java_net_PlainDatagramSocketImpl
177 * Method: bind
178 * Signature: (ILjava/net/InetAddress;)V
179 */
180 JNIEXPORT void JNICALL
181 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
182 jint localport, jobject iaObj) {
183 /* fdObj is the FileDescriptor field on this */
184 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
185 /* fd is an int field on fdObj */
186 int fd;
187 int len = 0;
188 SOCKADDR him;
189 socklen_t slen = sizeof(him);
190
191 if (IS_NULL(fdObj)) {
192 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
193 "Socket closed");
194 return;
195 } else {
196 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
197 }
198
199 if (IS_NULL(iaObj)) {
200 JNU_ThrowNullPointerException(env, "iaObj is null.");
201 return;
202 }
203
204 /* bind */
205 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
206 return;
207 }
208 setDefaultScopeID(env, (struct sockaddr *)&him);
209
210 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
211 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
212 errno == EPERM || errno == EACCES) {
213 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
214 "Bind failed");
215 } else {
216 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
217 "Bind failed");
218 }
219 return;
220 }
221
222 /* initialize the local port */
223 if (localport == 0) {
224 /* Now that we're a connected socket, let's extract the port number
225 * that the system chose for us and store it in the Socket object.
226 */
227 if (getsockname(fd, (struct sockaddr *)&him, &slen) == -1) {
228 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
229 "Error getting socket name");
230 return;
231 }
232
233 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
234
235 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
236 } else {
237 (*env)->SetIntField(env, this, pdsi_localPortID, localport);
238 }
239 }
240
241 /*
242 * Class: java_net_PlainDatagramSocketImpl
243 * Method: connect0
244 * Signature: (Ljava/net/InetAddress;I)V
245 */
246 JNIEXPORT void JNICALL
247 Java_java_net_PlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
255 int len = 0;
256
257 if (IS_NULL(fdObj)) {
258 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
259 "Socket closed");
260 return;
261 }
262 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
263
264 if (IS_NULL(address)) {
265 JNU_ThrowNullPointerException(env, "address");
266 return;
267 }
268
269 if (NET_InetAddressToSockaddr(env, address, port, (struct sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
270 return;
271 }
272
273 setDefaultScopeID(env, (struct sockaddr *)&rmtaddr);
274
275 if (NET_Connect(fd, (struct sockaddr *)&rmtaddr, len) == -1) {
276 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
277 "Connect failed");
278 return;
279 }
280
281 }
282
283 /*
284 * Class: java_net_PlainDatagramSocketImpl
285 * Method: disconnect0
286 * Signature: ()V
287 */
288 JNIEXPORT void JNICALL
289 Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
290 /* The object's field */
291 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
292 /* The fdObj'fd */
293 jint fd;
294
295 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
296 SOCKADDR addr;
297 socklen_t len;
298 #endif
299
300 if (IS_NULL(fdObj)) {
301 return;
302 }
303 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
304
305 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
306 memset(&addr, 0, sizeof(addr));
307 #ifdef AF_INET6
308 if (ipv6_available()) {
309 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&addr;
310 him6->sin6_family = AF_UNSPEC;
311 len = sizeof(struct sockaddr_in6);
312 } else
313 #endif
314 {
315 struct sockaddr_in *him4 = (struct sockaddr_in*)&addr;
316 him4->sin_family = AF_UNSPEC;
317 len = sizeof(struct sockaddr_in);
318 }
319 NET_Connect(fd, (struct sockaddr *)&addr, len);
320
321 #ifdef __linux__
322 int localPort = 0;
323 if (getsockname(fd, (struct sockaddr *)&addr, &len) == -1)
324 return;
325
326 localPort = NET_GetPortFromSockaddr((struct sockaddr *)&addr);
327 if (localPort == 0) {
328 localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
329 #ifdef AF_INET6
330 if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
331 ((struct sockaddr_in6*)&addr)->sin6_port = htons(localPort);
332 } else
333 #endif /* AF_INET6 */
334 {
335 ((struct sockaddr_in*)&addr)->sin_port = htons(localPort);
336 }
337
338 NET_Bind(fd, (struct sockaddr *)&addr, len);
339 }
340
341 #endif
342 #else
343 NET_Connect(fd, 0, 0);
344 #endif
345 }
346
347 /*
348 * Class: java_net_PlainDatagramSocketImpl
349 * Method: send
350 * Signature: (Ljava/net/DatagramPacket;)V
351 */
352 JNIEXPORT void JNICALL
353 Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
354 jobject packet) {
355
356 char BUF[MAX_BUFFER_LEN];
357 char *fullPacket = NULL;
358 int ret, mallocedPacket = JNI_FALSE;
359 /* The object's field */
360 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
361 jint trafficClass = (*env)->GetIntField(env, this, pdsi_trafficClassID);
362
363 jbyteArray packetBuffer;
440 (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
441 (jbyte *)fullPacket);
442 #ifdef AF_INET6
443 if (trafficClass != 0 && ipv6_available()) {
444 NET_SetTrafficClass((struct sockaddr *)&rmtaddr, trafficClass);
445 }
446 #endif /* AF_INET6 */
447
448
449 /*
450 * Send the datagram.
451 *
452 * If we are connected it's possible that sendto will return
453 * ECONNREFUSED indicating that an ICMP port unreachable has
454 * received.
455 */
456 ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
457 (struct sockaddr *)rmtaddrP, len);
458
459 if (ret < 0) {
460 if (errno == ECONNREFUSED) {
461 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
462 "ICMP Port Unreachable");
463 } else {
464 NET_ThrowByNameWithLastError(env, "java/io/IOException", "sendto failed");
465 }
466 }
467
468 if (mallocedPacket) {
469 free(fullPacket);
470 }
471 return;
472 }
473
474 /*
475 * Class: java_net_PlainDatagramSocketImpl
476 * Method: peek
477 * Signature: (Ljava/net/InetAddress;)I
478 */
479 JNIEXPORT jint JNICALL
480 Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
481 jobject addressObj) {
482
483 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
484 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
485 jint fd;
486 ssize_t n;
487 SOCKADDR remote_addr;
488 socklen_t slen = SOCKADDR_LEN;
489 char buf[1];
490 jint family;
491 jobject iaObj;
492 int port;
493 if (IS_NULL(fdObj)) {
494 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
495 return -1;
496 } else {
497 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
498 }
499 if (IS_NULL(addressObj)) {
500 JNU_ThrowNullPointerException(env, "Null address in peek()");
501 return -1;
502 }
503 if (timeout) {
504 int ret = NET_Timeout(fd, timeout);
505 if (ret == 0) {
506 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
507 "Peek timed out");
508 return ret;
509 } else if (ret == -1) {
510 if (errno == EBADF) {
511 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
512 } else {
513 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
514 }
515 return ret;
516 }
517 }
518
519 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, (struct sockaddr *)&remote_addr, &slen);
520
521 if (n == -1) {
522
523 #ifdef __solaris__
524 if (errno == ECONNREFUSED) {
525 int orig_errno = errno;
526 (void) recv(fd, buf, 1, 0);
527 errno = orig_errno;
528 }
529 #endif
530 if (errno == ECONNREFUSED) {
531 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
532 "ICMP Port Unreachable");
533 } else {
534 if (errno == EBADF) {
535 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
536 } else {
537 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Peek failed");
538 }
539 }
540 return 0;
541 }
542
543 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
544 #ifdef AF_INET6
545 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
546 #else
547 family = AF_INET;
548 #endif
549 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
550 int address = getInetAddress_addr(env, iaObj);
551 setInetAddress_addr(env, addressObj, address);
552 }
553 return port;
554 }
555
556 JNIEXPORT jint JNICALL
557 Java_java_net_PlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
558 jobject packet) {
559
560 char BUF[MAX_BUFFER_LEN];
561 char *fullPacket = NULL;
562 int mallocedPacket = JNI_FALSE;
563 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
564 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
565
566 jbyteArray packetBuffer;
567 jint packetBufferOffset, packetBufferLen;
568
569 int fd;
570
571 int n;
572 SOCKADDR remote_addr;
573 socklen_t slen = SOCKADDR_LEN;
574 int port;
575
576 if (IS_NULL(fdObj)) {
577 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
578 "Socket closed");
579 return -1;
580 }
581
582 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
583
584 if (IS_NULL(packet)) {
585 JNU_ThrowNullPointerException(env, "packet");
586 return -1;
587 }
588
589 packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
590 if (IS_NULL(packetBuffer)) {
591 JNU_ThrowNullPointerException(env, "packet buffer");
592 return -1;
593 }
594 packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
595 packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
596 if (timeout) {
597 int ret = NET_Timeout(fd, timeout);
598 if (ret == 0) {
599 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
600 "Receive timed out");
601 return -1;
602 } else if (ret == -1) {
603 #ifdef __linux__
604 if (errno == EBADF) {
605 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
606 } else {
607 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
608 }
609 #else
610 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
611 #endif
612 return -1;
613 }
614 }
615
616 if (packetBufferLen > MAX_BUFFER_LEN) {
617
618 /* When JNI-ifying the JDK's IO routines, we turned
619 * reads and writes of byte arrays of size greater
620 * than 2048 bytes into several operations of size 2048.
621 * This saves a malloc()/memcpy()/free() for big
622 * buffers. This is OK for file IO and TCP, but that
623 * strategy violates the semantics of a datagram protocol.
624 * (one big send) != (several smaller sends). So here
625 * we *must* allocate the buffer. Note it needn't be bigger
626 * than 65,536 (0xFFFF), the max size of an IP packet.
627 * anything bigger is truncated anyway.
628 *
629 * We may want to use a smarter allocation scheme at some
630 * point.
631 */
632 if (packetBufferLen > MAX_PACKET_LEN) {
633 packetBufferLen = MAX_PACKET_LEN;
634 }
635 fullPacket = (char *)malloc(packetBufferLen);
636
637 if (!fullPacket) {
638 JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
639 return -1;
640 } else {
641 mallocedPacket = JNI_TRUE;
642 }
643 } else {
644 fullPacket = &(BUF[0]);
645 }
646
647 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
648 (struct sockaddr *)&remote_addr, &slen);
649 /* truncate the data if the packet's length is too small */
650 if (n > packetBufferLen) {
651 n = packetBufferLen;
652 }
653 if (n == -1) {
654
655 #ifdef __solaris__
656 if (errno == ECONNREFUSED) {
657 int orig_errno = errno;
658 (void) recv(fd, fullPacket, 1, 0);
659 errno = orig_errno;
660 }
661 #endif
662 (*env)->SetIntField(env, packet, dp_offsetID, 0);
663 (*env)->SetIntField(env, packet, dp_lengthID, 0);
664 if (errno == ECONNREFUSED) {
665 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
666 "ICMP Port Unreachable");
667 } else {
668 if (errno == EBADF) {
669 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
670 } else {
671 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
672 }
673 }
674 } else {
675 /*
676 * success - fill in received address...
677 *
678 * REMIND: Fill in an int on the packet, and create inetadd
679 * object in Java, as a performance improvement. Also
680 * construct the inetadd object lazily.
681 */
682
683 jobject packetAddress;
684
685 /*
686 * Check if there is an InetAddress already associated with this
687 * packet. If so we check if it is the same source address. We
688 * can't update any existing InetAddress because it is immutable
689 */
690 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
691 if (packetAddress != NULL) {
692 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
693 /* force a new InetAddress to be created */
720 * Method: receive
721 * Signature: (Ljava/net/DatagramPacket;)V
722 */
723 JNIEXPORT void JNICALL
724 Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
725 jobject packet) {
726
727 char BUF[MAX_BUFFER_LEN];
728 char *fullPacket = NULL;
729 int mallocedPacket = JNI_FALSE;
730 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
731 jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
732
733 jbyteArray packetBuffer;
734 jint packetBufferOffset, packetBufferLen;
735
736 int fd;
737
738 int n;
739 SOCKADDR remote_addr;
740 socklen_t slen = SOCKADDR_LEN;
741 jboolean retry;
742 #ifdef __linux__
743 jboolean connected = JNI_FALSE;
744 jobject connectedAddress = NULL;
745 jint connectedPort = 0;
746 jlong prevTime = 0;
747 #endif
748
749 if (IS_NULL(fdObj)) {
750 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
751 "Socket closed");
752 return;
753 }
754
755 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
756
757 if (IS_NULL(packet)) {
758 JNU_ThrowNullPointerException(env, "packet");
759 return;
760 }
790
791 if (!fullPacket) {
792 JNU_ThrowOutOfMemoryError(env, "Receive buffer native heap allocation failed");
793 return;
794 } else {
795 mallocedPacket = JNI_TRUE;
796 }
797 } else {
798 fullPacket = &(BUF[0]);
799 }
800
801 do {
802 retry = JNI_FALSE;
803
804 if (timeout) {
805 int ret = NET_Timeout(fd, timeout);
806 if (ret <= 0) {
807 if (ret == 0) {
808 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
809 "Receive timed out");
810 } else if (ret == -1) {
811 #ifdef __linux__
812 if (errno == EBADF) {
813 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
814 } else {
815 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
816 }
817 #else
818 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
819 #endif
820 }
821
822 if (mallocedPacket) {
823 free(fullPacket);
824 }
825
826 return;
827 }
828 }
829
830 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,
831 (struct sockaddr *)&remote_addr, &slen);
832 /* truncate the data if the packet's length is too small */
833 if (n > packetBufferLen) {
834 n = packetBufferLen;
835 }
836 if (n == -1) {
837 (*env)->SetIntField(env, packet, dp_offsetID, 0);
838 (*env)->SetIntField(env, packet, dp_lengthID, 0);
839 if (errno == ECONNREFUSED) {
840 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
841 "ICMP Port Unreachable");
842 } else {
843 if (errno == EBADF) {
844 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
845 } else {
846 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");
847 }
848 }
849 } else {
850 int port;
851 jobject packetAddress;
852
853 /*
854 * success - fill in received address...
855 *
856 * REMIND: Fill in an int on the packet, and create inetadd
857 * object in Java, as a performance improvement. Also
858 * construct the inetadd object lazily.
859 */
860
861 /*
862 * Check if there is an InetAddress already associated with this
863 * packet. If so we check if it is the same source address. We
864 * can't update any existing InetAddress because it is immutable
865 */
866 packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
867 if (packetAddress != NULL) {
868 if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
897 * Method: datagramSocketCreate
898 * Signature: ()V
899 */
900 JNIEXPORT void JNICALL
901 Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
902 jobject this) {
903 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
904 int arg, fd, t = 1;
905 #ifdef AF_INET6
906 int domain = ipv6_available() ? AF_INET6 : AF_INET;
907 #else
908 int domain = AF_INET;
909 #endif
910
911 if (IS_NULL(fdObj)) {
912 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
913 "Socket closed");
914 return;
915 }
916
917 if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
918 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
919 "Error creating socket");
920 return;
921 }
922
923 #ifdef AF_INET6
924 /* Disable IPV6_V6ONLY to ensure dual-socket support */
925 if (domain == AF_INET6) {
926 arg = 0;
927 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
928 sizeof(int)) < 0) {
929 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
930 close(fd);
931 return;
932 }
933 }
934 #endif /* AF_INET6 */
935
936 #ifdef __APPLE__
937 arg = 65507;
938 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
939 (char *)&arg, sizeof(arg)) < 0) {
940 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
941 strerror(errno));
942 return;
943 }
944 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
945 (char *)&arg, sizeof(arg)) < 0) {
946 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
947 strerror(errno));
948 return;
949 }
950 #endif /* __APPLE__ */
951
952 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
953
954 #if defined(__linux__)
955 arg = 0;
956 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
957 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
958 (errno != ENOPROTOOPT)) {
959 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
960 strerror(errno));
961 close(fd);
962 return;
963 }
964 #endif
1031 * Check that there is at least one address bound to this
1032 * interface.
1033 */
1034 if (len < 1) {
1035 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1036 "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1037 return;
1038 }
1039
1040 /*
1041 * We need an ipv4 address here
1042 */
1043 for (i = 0; i < len; i++) {
1044 addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1045 if (getInetAddress_family(env, addr) == IPv4) {
1046 in.s_addr = htonl(getInetAddress_addr(env, addr));
1047 break;
1048 }
1049 }
1050
1051 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1052 (const char*)&in, sizeof(in)) < 0) {
1053 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1054 "Error setting socket option");
1055 }
1056 }
1057
1058 /*
1059 * Set outgoing multicast interface designated by a NetworkInterface.
1060 * Throw exception if failed.
1061 */
1062 #ifdef AF_INET6
1063 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1064 static jfieldID ni_indexID;
1065 int index;
1066
1067 if (ni_indexID == NULL) {
1068 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1069 CHECK_NULL(c);
1070 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1071 CHECK_NULL(ni_indexID);
1072 }
1073 index = (*env)->GetIntField(env, value, ni_indexID);
1074
1075 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1076 (const char*)&index, sizeof(index)) < 0) {
1077 if (errno == EINVAL && index > 0) {
1078 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1079 "IPV6_MULTICAST_IF failed (interface has IPv4 "
1080 "address only?)");
1081 } else {
1082 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1083 "Error setting socket option");
1084 }
1085 return;
1086 }
1087
1088 }
1089 #endif /* AF_INET6 */
1090
1091 /*
1092 * Set outgoing multicast interface designated by an InetAddress.
1093 * Throw exception if failed.
1094 */
1095 static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject value) {
1096 struct in_addr in;
1097
1098 in.s_addr = htonl( getInetAddress_addr(env, value) );
1099
1100 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1101 (const char*)&in, sizeof(in)) < 0) {
1102 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1103 "Error setting socket option");
1104 }
1105 }
1106
1107 /*
1108 * Set outgoing multicast interface designated by an InetAddress.
1109 * Throw exception if failed.
1110 */
1111 #ifdef AF_INET6
1112 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) {
1113 static jclass ni_class;
1114 if (ni_class == NULL) {
1115 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1116 CHECK_NULL(c);
1117 ni_class = (*env)->NewGlobalRef(env, c);
1118 CHECK_NULL(ni_class);
1119 }
1120
1429 #endif
1430
1431 /*
1432 * IPv4 implementation
1433 */
1434 if (isIPV4) {
1435 static jclass inet4_class;
1436 static jmethodID inet4_ctrID;
1437
1438 static jclass ni_class;
1439 static jmethodID ni_ctrID;
1440 static jfieldID ni_indexID;
1441 static jfieldID ni_addrsID;
1442
1443 jobjectArray addrArray;
1444 jobject addr;
1445 jobject ni;
1446
1447 struct in_addr in;
1448 struct in_addr *inP = ∈
1449 socklen_t len = sizeof(struct in_addr);
1450
1451 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1452 (char *)inP, &len) < 0) {
1453 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1454 "Error getting socket option");
1455 return NULL;
1456 }
1457
1458 /*
1459 * Construct and populate an Inet4Address
1460 */
1461 if (inet4_class == NULL) {
1462 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1463 CHECK_NULL_RETURN(c, NULL);
1464 inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1465 CHECK_NULL_RETURN(inet4_ctrID, NULL);
1466 inet4_class = (*env)->NewGlobalRef(env, c);
1467 CHECK_NULL_RETURN(inet4_class, NULL);
1468 }
1469 addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1470 CHECK_NULL_RETURN(addr, NULL);
1471
1515 (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1516 return ni;
1517 }
1518
1519
1520 #ifdef AF_INET6
1521 /*
1522 * IPv6 implementation
1523 */
1524 if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1525 (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1526
1527 static jclass ni_class;
1528 static jmethodID ni_ctrID;
1529 static jfieldID ni_indexID;
1530 static jfieldID ni_addrsID;
1531 static jclass ia_class;
1532 static jmethodID ia_anyLocalAddressID;
1533
1534 int index;
1535 socklen_t len = sizeof(index);
1536
1537 jobjectArray addrArray;
1538 jobject addr;
1539 jobject ni;
1540
1541 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1542 (char*)&index, &len) < 0) {
1543 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1544 "Error getting socket option");
1545 return NULL;
1546 }
1547
1548 if (ni_class == NULL) {
1549 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1550 CHECK_NULL_RETURN(c, NULL);
1551 ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1552 CHECK_NULL_RETURN(ni_ctrID, NULL);
1553 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1554 CHECK_NULL_RETURN(ni_indexID, NULL);
1555 ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1556 "[Ljava/net/InetAddress;");
1557 CHECK_NULL_RETURN(ni_addrsID, NULL);
1558
1559 ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1560 CHECK_NULL_RETURN(ia_class, NULL);
1561 ia_class = (*env)->NewGlobalRef(env, ia_class);
1736
1737 /*
1738 * Multicast-related calls
1739 */
1740
1741 JNIEXPORT void JNICALL
1742 Java_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
1743 jbyte ttl) {
1744 jint ittl = ttl;
1745 if (ittl < 0) {
1746 ittl += 0x100;
1747 }
1748 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, ittl);
1749 }
1750
1751 /*
1752 * Set TTL for a socket. Throw exception if failed.
1753 */
1754 static void setTTL(JNIEnv *env, int fd, jint ttl) {
1755 char ittl = (char)ttl;
1756 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
1757 sizeof(ittl)) < 0) {
1758 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1759 "Error setting socket option");
1760 }
1761 }
1762
1763 /*
1764 * Set hops limit for a socket. Throw exception if failed.
1765 */
1766 #ifdef AF_INET6
1767 static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
1768 int ittl = (int)ttl;
1769 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1770 (char*)&ittl, sizeof(ittl)) < 0) {
1771 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1772 "Error setting socket option");
1773 }
1774 }
1775 #endif
1776
1777 /*
1778 * Class: java_net_PlainDatagramSocketImpl
1779 * Method: setTTL
1780 * Signature: (B)V
1781 */
1782 JNIEXPORT void JNICALL
1783 Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
1784 jint ttl) {
1785
1786 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1787 int fd;
1788 /* it is important to cast this to a char, otherwise setsockopt gets confused */
1789
1830 * Method: getTTL
1831 * Signature: ()B
1832 */
1833 JNIEXPORT jint JNICALL
1834 Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
1835
1836 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1837 jint fd = -1;
1838
1839 if (IS_NULL(fdObj)) {
1840 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1841 "Socket closed");
1842 return -1;
1843 } else {
1844 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1845 }
1846 /* getsockopt of TTL */
1847 #ifdef AF_INET6
1848 if (ipv6_available()) {
1849 int ttl = 0;
1850 socklen_t len = sizeof(ttl);
1851
1852 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1853 (char*)&ttl, &len) < 0) {
1854 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1855 "Error getting socket option");
1856 return -1;
1857 }
1858 return (jint)ttl;
1859 } else
1860 #endif /* AF_INET6 */
1861 {
1862 u_char ttl = 0;
1863 socklen_t len = sizeof(ttl);
1864 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
1865 (char*)&ttl, &len) < 0) {
1866 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1867 "Error getting socket option");
1868 return -1;
1869 }
1870 return (jint)ttl;
1871 }
1872 }
1873
1874
1875 /*
1876 * mcast_join_leave: Join or leave a multicast group.
1877 *
1878 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1879 * to join/leave multicast group.
1880 *
1881 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1882 * to join/leave multicast group. If multicast group is an IPv4 address then
1883 * an IPv4-mapped address is used.
1884 *
1997 /*
1998 * joinGroup(InetAddress) implementation :-
1999 *
2000 * Linux/IPv6: use ip_mreqn structure populated with multicast
2001 * address and interface index. index obtained
2002 * from cached value or IPV6_MULTICAST_IF.
2003 *
2004 * IPv4: use ip_mreq structure populated with multicast
2005 * address and local address obtained from
2006 * IP_MULTICAST_IF. On Linux IP_MULTICAST_IF
2007 * returns different structure depending on
2008 * kernel.
2009 */
2010
2011 if (niObj == NULL) {
2012
2013 #if defined(__linux__) && defined(AF_INET6)
2014 if (ipv6_available()) {
2015
2016 int index;
2017 socklen_t len = sizeof(index);
2018
2019 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2020 (char*)&index, &len) < 0) {
2021 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2022 return;
2023 }
2024
2025 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2026 mname.imr_address.s_addr = 0 ;
2027 mname.imr_ifindex = index;
2028 mname_len = sizeof(struct ip_mreqn);
2029 } else
2030 #endif
2031 {
2032 struct in_addr in;
2033 struct in_addr *inP = ∈
2034 socklen_t len = sizeof(struct in_addr);
2035
2036 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)inP, &len) < 0) {
2037 NET_ThrowCurrent(env, "getsockopt IP_MULTICAST_IF failed");
2038 return;
2039 }
2040
2041 #ifdef __linux__
2042 mname.imr_address.s_addr = in.s_addr;
2043
2044 #else
2045 mname.imr_interface.s_addr = in.s_addr;
2046 #endif
2047 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
2048 mname_len = sizeof(struct ip_mreq);
2049 }
2050 }
2051
2052
2053 /*
2054 * Join the multicast group.
2055 */
2056 if (setsockopt(fd, IPPROTO_IP, (join ? IP_ADD_MEMBERSHIP:IP_DROP_MEMBERSHIP),
2057 (char *) &mname, mname_len) < 0) {
2058
2059 /*
2060 * If IP_ADD_MEMBERSHIP returns ENOPROTOOPT on Linux and we've got
2061 * IPv6 enabled then it's possible that the kernel has been fixed
2062 * so we switch to IPV6_ADD_MEMBERSHIP socket option.
2063 * As of 2.4.7 kernel IPV6_ADD_MEMBERSHIP can't handle IPv4-mapped
2064 * addresses so we have to use IP_ADD_MEMBERSHIP for IPv4 multicast
2065 * groups. However if the socket is an IPv6 socket then then setsockopt
2066 * should return ENOPROTOOPT. We assume this will be fixed in Linux
2067 * at some stage.
2068 */
2069 #if defined(__linux__) && defined(AF_INET6)
2070 if (errno == ENOPROTOOPT) {
2071 if (ipv6_available()) {
2072 ipv6_join_leave = JNI_TRUE;
2073 errno = 0;
2074 } else {
2075 errno = ENOPROTOOPT; /* errno can be changed by ipv6_available */
2076 }
2112 jint address;
2113 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
2114 if (family == AF_INET) { /* will convert to IPv4-mapped address */
2115 memset((char *) caddr, 0, 16);
2116 address = getInetAddress_addr(env, iaObj);
2117
2118 caddr[10] = 0xff;
2119 caddr[11] = 0xff;
2120
2121 caddr[12] = ((address >> 24) & 0xff);
2122 caddr[13] = ((address >> 16) & 0xff);
2123 caddr[14] = ((address >> 8) & 0xff);
2124 caddr[15] = (address & 0xff);
2125 } else {
2126 getInet6Address_ipaddress(env, iaObj, (char*)caddr);
2127 }
2128
2129 memcpy((void *)&(mname6.ipv6mr_multiaddr), caddr, sizeof(struct in6_addr));
2130 if (IS_NULL(niObj)) {
2131 int index;
2132 socklen_t len = sizeof(index);
2133
2134 if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2135 (char*)&index, &len) < 0) {
2136 NET_ThrowCurrent(env, "getsockopt IPV6_MULTICAST_IF failed");
2137 return;
2138 }
2139
2140 #ifdef __linux__
2141 /*
2142 * On 2.4.8+ if we join a group with the interface set to 0
2143 * then the kernel records the interface it decides. This causes
2144 * subsequent leave groups to fail as there is no match. Thus we
2145 * pick the interface if there is a matching route.
2146 */
2147 if (index == 0) {
2148 int rt_index = getDefaultIPv6Interface(&(mname6.ipv6mr_multiaddr));
2149 if (rt_index > 0) {
2150 index = rt_index;
2151 }
2152 }
2153 #endif
2154 #ifdef MACOSX
2158 #endif
2159 mname6.ipv6mr_interface = index;
2160 } else {
2161 jint idx = (*env)->GetIntField(env, niObj, ni_indexID);
2162 mname6.ipv6mr_interface = idx;
2163 }
2164
2165 #if defined(_ALLBSD_SOURCE)
2166 #define ADD_MEMBERSHIP IPV6_JOIN_GROUP
2167 #define DRP_MEMBERSHIP IPV6_LEAVE_GROUP
2168 #define S_ADD_MEMBERSHIP "IPV6_JOIN_GROUP"
2169 #define S_DRP_MEMBERSHIP "IPV6_LEAVE_GROUP"
2170 #else
2171 #define ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
2172 #define DRP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
2173 #define S_ADD_MEMBERSHIP "IPV6_ADD_MEMBERSHIP"
2174 #define S_DRP_MEMBERSHIP "IPV6_DROP_MEMBERSHIP"
2175 #endif
2176
2177 /* Join the multicast group */
2178 if (setsockopt(fd, IPPROTO_IPV6, (join ? ADD_MEMBERSHIP : DRP_MEMBERSHIP),
2179 (char *) &mname6, sizeof (mname6)) < 0) {
2180
2181 if (join) {
2182 NET_ThrowCurrent(env, "setsockopt " S_ADD_MEMBERSHIP " failed");
2183 } else {
2184 if (errno == ENOENT) {
2185 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2186 "Not a member of the multicast group");
2187 } else {
2188 NET_ThrowCurrent(env, "setsockopt " S_DRP_MEMBERSHIP " failed");
2189 }
2190 }
2191 }
2192 }
2193 #endif
2194 }
2195
2196 /*
2197 * Class: java_net_PlainDatagramSocketImpl
2198 * Method: join
|