1 /*
2 * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29
30 #if defined(__solaris__)
31 #include <sys/filio.h>
32 #endif
33
34 #include "net_util.h"
35
36 #include "java_net_PlainDatagramSocketImpl.h"
37 #include "java_net_InetAddress.h"
38 #include "java_net_NetworkInterface.h"
39 #include "java_net_SocketOptions.h"
40
41 #ifdef __linux__
42 #define IPV6_MULTICAST_IF 17
43 #ifndef SO_BSDCOMPAT
44 #define SO_BSDCOMPAT 14
45 #endif
46 /**
47 * IP_MULTICAST_ALL has been supported since kernel version 2.6.31
48 * but we may be building on a machine that is older than that.
49 */
50 #ifndef IP_MULTICAST_ALL
51 #define IP_MULTICAST_ALL 49
52 #endif
53 #endif // __linux__
54
55 #ifdef __solaris__
56 #ifndef BSD_COMP
57 #define BSD_COMP
58 #endif
59 #endif
60
61 #ifndef IPTOS_TOS_MASK
62 #define IPTOS_TOS_MASK 0x1e
63 #endif
64 #ifndef IPTOS_PREC_MASK
65 #define IPTOS_PREC_MASK 0xe0
66 #endif
67
68 /************************************************************************
69 * PlainDatagramSocketImpl
70 */
71
72 static jfieldID IO_fd_fdID;
73
74 static jfieldID pdsi_fdID;
75 static jfieldID pdsi_timeoutID;
76 static jfieldID pdsi_trafficClassID;
77 static jfieldID pdsi_localPortID;
78 static jfieldID pdsi_connected;
79 static jfieldID pdsi_connectedAddress;
80 static jfieldID pdsi_connectedPort;
481 if (ret == 0) {
482 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
483 "Peek timed out");
484 return ret;
485 } else if (ret == -1) {
486 if (errno == EBADF) {
487 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
488 } else if (errno == ENOMEM) {
489 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
490 } else {
491 JNU_ThrowByNameWithMessageAndLastError
492 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
493 }
494 return ret;
495 }
496 }
497
498 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, &rmtaddr.sa, &slen);
499
500 if (n == -1) {
501
502 #ifdef __solaris__
503 if (errno == ECONNREFUSED) {
504 int orig_errno = errno;
505 recv(fd, buf, 1, 0);
506 errno = orig_errno;
507 }
508 #endif
509 if (errno == ECONNREFUSED) {
510 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
511 "ICMP Port Unreachable");
512 } else {
513 if (errno == EBADF) {
514 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
515 } else {
516 JNU_ThrowByNameWithMessageAndLastError
517 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
518 }
519 }
520 return 0;
521 }
522
523 iaObj = NET_SockaddrToInetAddress(env, &rmtaddr, &port);
524 family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ?
525 AF_INET : AF_INET6;
526 JNU_CHECK_EXCEPTION_RETURN(env, -1);
527 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
528 int address = getInetAddress_addr(env, iaObj);
615 }
616 fullPacket = (char *)malloc(packetBufferLen);
617
618 if (!fullPacket) {
619 JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
620 return -1;
621 } else {
622 mallocedPacket = JNI_TRUE;
623 }
624 } else {
625 fullPacket = &(BUF[0]);
626 }
627
628 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
629 &rmtaddr.sa, &slen);
630 /* truncate the data if the packet's length is too small */
631 if (n > packetBufferLen) {
632 n = packetBufferLen;
633 }
634 if (n == -1) {
635
636 #ifdef __solaris__
637 if (errno == ECONNREFUSED) {
638 int orig_errno = errno;
639 (void) recv(fd, fullPacket, 1, 0);
640 errno = orig_errno;
641 }
642 #endif
643 (*env)->SetIntField(env, packet, dp_offsetID, 0);
644 (*env)->SetIntField(env, packet, dp_lengthID, 0);
645 if (errno == ECONNREFUSED) {
646 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
647 "ICMP Port Unreachable");
648 } else {
649 if (errno == EBADF) {
650 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
651 } else {
652 JNU_ThrowByNameWithMessageAndLastError
653 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
654 }
655 }
656 } else {
657 /*
658 * success - fill in received address...
659 *
660 * REMIND: Fill in an int on the packet, and create inetadd
661 * object in Java, as a performance improvement. Also
662 * construct the inetadd object lazily.
1836 }
1837 return (jint)ttl;
1838 }
1839 }
1840
1841
1842 /*
1843 * mcast_join_leave: Join or leave a multicast group.
1844 *
1845 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1846 * to join/leave multicast group.
1847 *
1848 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1849 * to join/leave multicast group. If multicast group is an IPv4 address then
1850 * an IPv4-mapped address is used.
1851 *
1852 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1853 * we must use the IPv4 socket options. This is because the IPv6 socket options
1854 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
1855 * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP
1856 * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris
1857 * already does this). Thus to cater for this we first try with the IPv4
1858 * socket options and if they fail we use the IPv6 socket options. This
1859 * seems a reasonable failsafe solution.
1860 */
1861 static void mcast_join_leave(JNIEnv *env, jobject this,
1862 jobject iaObj, jobject niObj,
1863 jboolean join) {
1864
1865 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1866 jint fd;
1867 jint family;
1868 jint ipv6_join_leave;
1869
1870 if (IS_NULL(fdObj)) {
1871 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1872 "Socket closed");
1873 return;
1874 } else {
1875 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1876 }
1877 if (IS_NULL(iaObj)) {
1878 JNU_ThrowNullPointerException(env, "iaObj");
1879 return;
|
1 /*
2 * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29
30 #include "net_util.h"
31
32 #include "java_net_PlainDatagramSocketImpl.h"
33 #include "java_net_InetAddress.h"
34 #include "java_net_NetworkInterface.h"
35 #include "java_net_SocketOptions.h"
36
37 #ifdef __linux__
38 #define IPV6_MULTICAST_IF 17
39 #ifndef SO_BSDCOMPAT
40 #define SO_BSDCOMPAT 14
41 #endif
42 /**
43 * IP_MULTICAST_ALL has been supported since kernel version 2.6.31
44 * but we may be building on a machine that is older than that.
45 */
46 #ifndef IP_MULTICAST_ALL
47 #define IP_MULTICAST_ALL 49
48 #endif
49 #endif // __linux__
50
51 #ifndef IPTOS_TOS_MASK
52 #define IPTOS_TOS_MASK 0x1e
53 #endif
54 #ifndef IPTOS_PREC_MASK
55 #define IPTOS_PREC_MASK 0xe0
56 #endif
57
58 /************************************************************************
59 * PlainDatagramSocketImpl
60 */
61
62 static jfieldID IO_fd_fdID;
63
64 static jfieldID pdsi_fdID;
65 static jfieldID pdsi_timeoutID;
66 static jfieldID pdsi_trafficClassID;
67 static jfieldID pdsi_localPortID;
68 static jfieldID pdsi_connected;
69 static jfieldID pdsi_connectedAddress;
70 static jfieldID pdsi_connectedPort;
471 if (ret == 0) {
472 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
473 "Peek timed out");
474 return ret;
475 } else if (ret == -1) {
476 if (errno == EBADF) {
477 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
478 } else if (errno == ENOMEM) {
479 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
480 } else {
481 JNU_ThrowByNameWithMessageAndLastError
482 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
483 }
484 return ret;
485 }
486 }
487
488 n = NET_RecvFrom(fd, buf, 1, MSG_PEEK, &rmtaddr.sa, &slen);
489
490 if (n == -1) {
491 if (errno == ECONNREFUSED) {
492 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
493 "ICMP Port Unreachable");
494 } else {
495 if (errno == EBADF) {
496 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
497 } else {
498 JNU_ThrowByNameWithMessageAndLastError
499 (env, JNU_JAVANETPKG "SocketException", "Peek failed");
500 }
501 }
502 return 0;
503 }
504
505 iaObj = NET_SockaddrToInetAddress(env, &rmtaddr, &port);
506 family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ?
507 AF_INET : AF_INET6;
508 JNU_CHECK_EXCEPTION_RETURN(env, -1);
509 if (family == AF_INET) { /* this API can't handle IPV6 addresses */
510 int address = getInetAddress_addr(env, iaObj);
597 }
598 fullPacket = (char *)malloc(packetBufferLen);
599
600 if (!fullPacket) {
601 JNU_ThrowOutOfMemoryError(env, "Peek buffer native heap allocation failed");
602 return -1;
603 } else {
604 mallocedPacket = JNI_TRUE;
605 }
606 } else {
607 fullPacket = &(BUF[0]);
608 }
609
610 n = NET_RecvFrom(fd, fullPacket, packetBufferLen, MSG_PEEK,
611 &rmtaddr.sa, &slen);
612 /* truncate the data if the packet's length is too small */
613 if (n > packetBufferLen) {
614 n = packetBufferLen;
615 }
616 if (n == -1) {
617 (*env)->SetIntField(env, packet, dp_offsetID, 0);
618 (*env)->SetIntField(env, packet, dp_lengthID, 0);
619 if (errno == ECONNREFUSED) {
620 JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
621 "ICMP Port Unreachable");
622 } else {
623 if (errno == EBADF) {
624 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
625 } else {
626 JNU_ThrowByNameWithMessageAndLastError
627 (env, JNU_JAVANETPKG "SocketException", "Receive failed");
628 }
629 }
630 } else {
631 /*
632 * success - fill in received address...
633 *
634 * REMIND: Fill in an int on the packet, and create inetadd
635 * object in Java, as a performance improvement. Also
636 * construct the inetadd object lazily.
1810 }
1811 return (jint)ttl;
1812 }
1813 }
1814
1815
1816 /*
1817 * mcast_join_leave: Join or leave a multicast group.
1818 *
1819 * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option
1820 * to join/leave multicast group.
1821 *
1822 * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option
1823 * to join/leave multicast group. If multicast group is an IPv4 address then
1824 * an IPv4-mapped address is used.
1825 *
1826 * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then
1827 * we must use the IPv4 socket options. This is because the IPv6 socket options
1828 * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7
1829 * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP
1830 * will be updated to return ENOPROTOOPT if uses with an IPv6 socket. Thus to
1831 * cater for this we first try with the IPv4 socket options and if they fail we
1832 * use the IPv6 socket options. This seems a reasonable failsafe solution.
1833 */
1834 static void mcast_join_leave(JNIEnv *env, jobject this,
1835 jobject iaObj, jobject niObj,
1836 jboolean join) {
1837
1838 jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1839 jint fd;
1840 jint family;
1841 jint ipv6_join_leave;
1842
1843 if (IS_NULL(fdObj)) {
1844 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1845 "Socket closed");
1846 return;
1847 } else {
1848 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1849 }
1850 if (IS_NULL(iaObj)) {
1851 JNU_ThrowNullPointerException(env, "iaObj");
1852 return;
|