1 /*
2 * Copyright (c) 2001, 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
26 package sun.nio.ch;
27
28 import java.io.IOException;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodHandles.Lookup;
31 import java.lang.invoke.VarHandle;
32 import java.net.DatagramPacket;
33 import java.net.DatagramSocket;
34 import java.net.DatagramSocketImpl;
35 import java.net.InetAddress;
36 import java.net.InetSocketAddress;
37 import java.net.NetworkInterface;
38 import java.net.SocketAddress;
39 import java.net.SocketException;
40 import java.net.SocketOption;
41 import java.net.StandardSocketOptions;
42 import java.nio.ByteBuffer;
43 import java.nio.channels.AlreadyConnectedException;
44 import java.nio.channels.ClosedChannelException;
45 import java.nio.channels.DatagramChannel;
46 import java.security.AccessController;
47 import java.security.PrivilegedAction;
48 import java.util.Set;
49
50 import static java.util.concurrent.TimeUnit.MILLISECONDS;
51
52 // Make a datagram-socket channel look like a datagram socket.
53 //
54 // The methods in this class are defined in exactly the same order as in
55 // java.net.DatagramSocket so as to simplify tracking future changes to that
56 // class.
57 //
58
59 class DatagramSocketAdaptor
60 extends DatagramSocket
61 {
62 // The channel being adapted
63 private final DatagramChannelImpl dc;
64
65 // Timeout "option" value for receives
66 private volatile int timeout;
67
68 // create DatagramSocket with useless impl
69 private DatagramSocketAdaptor(DatagramChannelImpl dc) {
70 super(new DummyDatagramSocketImpl());
71 this.dc = dc;
72 }
73
74 static DatagramSocket create(DatagramChannelImpl dc) {
75 return new DatagramSocketAdaptor(dc);
76 }
77
78 private void connectInternal(SocketAddress remote) throws SocketException {
79 try {
80 dc.connect(remote, false); // skips check for already connected
81 } catch (ClosedChannelException e) {
82 // ignore
83 } catch (Exception x) {
84 Net.translateToSocketException(x);
85 }
86 }
87
88 @Override
89 public void bind(SocketAddress local) throws SocketException {
90 if (local != null) {
91 local = Net.asInetSocketAddress(local);
92 } else {
93 local = new InetSocketAddress(0);
94 }
95 try {
392 public DatagramChannel getChannel() {
393 return dc;
394 }
395
396 @Override
397 public <T> DatagramSocket setOption(SocketOption<T> name, T value) throws IOException {
398 dc.setOption(name, value);
399 return this;
400 }
401
402 @Override
403 public <T> T getOption(SocketOption<T> name) throws IOException {
404 return dc.getOption(name);
405 }
406
407 @Override
408 public Set<SocketOption<?>> supportedOptions() {
409 return dc.supportedOptions();
410 }
411
412
413 /**
414 * DatagramSocketImpl implementation where all methods throw an error.
415 */
416 private static class DummyDatagramSocketImpl extends DatagramSocketImpl {
417 private static <T> T shouldNotGetHere() {
418 throw new InternalError("Should not get here");
419 }
420
421 @Override
422 protected void create() {
423 shouldNotGetHere();
424 }
425
426 @Override
427 protected void bind(int lport, InetAddress laddr) {
428 shouldNotGetHere();
429 }
430
431 @Override
432 protected void send(DatagramPacket p) {
433 shouldNotGetHere();
434 }
435
436 @Override
437 protected int peek(InetAddress address) {
438 return shouldNotGetHere();
439 }
440
441 @Override
442 protected int peekData(DatagramPacket p) {
443 return shouldNotGetHere();
444 }
445
446 @Override
447 protected void receive(DatagramPacket p) {
448 shouldNotGetHere();
449 }
450
451 @Deprecated
452 protected void setTTL(byte ttl) {
453 shouldNotGetHere();
454 }
455
456 @Deprecated
457 protected byte getTTL() {
458 return shouldNotGetHere();
459 }
460
461 @Override
462 protected void setTimeToLive(int ttl) {
463 shouldNotGetHere();
464 }
465
466 @Override
467 protected int getTimeToLive() {
468 return shouldNotGetHere();
469 }
470
471 @Override
472 protected void join(InetAddress group) {
473 shouldNotGetHere();
474 }
475
476 @Override
477 protected void leave(InetAddress inetaddr) {
478 shouldNotGetHere();
479 }
480
481 @Override
482 protected void joinGroup(SocketAddress group, NetworkInterface netIf) {
483 shouldNotGetHere();
484 }
485
486 @Override
487 protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) {
488 shouldNotGetHere();
489 }
490
491 @Override
492 protected void close() {
493 shouldNotGetHere();
494 }
495
496 @Override
497 public Object getOption(int optID) {
498 return shouldNotGetHere();
499 }
500
501 @Override
502 public void setOption(int optID, Object value) {
503 shouldNotGetHere();
504 }
505
506 @Override
507 protected <T> void setOption(SocketOption<T> name, T value) {
508 shouldNotGetHere();
509 }
510
511 @Override
512 protected <T> T getOption(SocketOption<T> name) {
513 return shouldNotGetHere();
514 }
515
516 @Override
517 protected Set<SocketOption<?>> supportedOptions() {
518 return shouldNotGetHere();
519 }
520 }
521
522 /**
523 * Defines static methods to get/set DatagramPacket fields and workaround
524 * DatagramPacket deficiencies.
525 */
526 private static class DatagramPackets {
527 private static final VarHandle LENGTH;
528 private static final VarHandle BUF_LENGTH;
529 static {
530 try {
531 PrivilegedAction<Lookup> pa = () -> {
532 try {
533 return MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
534 } catch (Exception e) {
535 throw new ExceptionInInitializerError(e);
536 }
537 };
538 MethodHandles.Lookup l = AccessController.doPrivileged(pa);
539 LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
540 BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
541 } catch (Exception e) {
542 throw new ExceptionInInitializerError(e);
543 }
544 }
545
546 /**
547 * Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be
548 * used at this time because it sets both the length and bufLength fields.
549 */
550 static void setLength(DatagramPacket p, int value) {
551 synchronized (p) {
552 LENGTH.set(p, value);
553 }
554 }
555
556 /**
557 * Returns the value of the DatagramPacket.bufLength field.
558 */
559 static int getBufLength(DatagramPacket p) {
560 synchronized (p) {
561 return (int) BUF_LENGTH.get(p);
562 }
563 }
564 }
565 }
|
1 /*
2 * Copyright (c) 2001, 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
26 package sun.nio.ch;
27
28 import java.io.IOException;
29 import java.lang.invoke.MethodHandle;
30 import java.lang.invoke.MethodHandles;
31 import java.lang.invoke.MethodHandles.Lookup;
32 import java.lang.invoke.MethodType;
33 import java.lang.invoke.VarHandle;
34 import java.net.DatagramPacket;
35 import java.net.DatagramSocket;
36 import java.net.InetAddress;
37 import java.net.InetSocketAddress;
38 import java.net.NetworkInterface;
39 import java.net.MulticastSocket;
40 import java.net.SocketAddress;
41 import java.net.SocketException;
42 import java.net.SocketOption;
43 import java.net.StandardSocketOptions;
44 import java.nio.ByteBuffer;
45 import java.nio.channels.AlreadyConnectedException;
46 import java.nio.channels.ClosedChannelException;
47 import java.nio.channels.DatagramChannel;
48 import java.nio.channels.MembershipKey;
49 import java.security.AccessController;
50 import java.security.PrivilegedAction;
51 import java.security.PrivilegedExceptionAction;
52 import java.util.Objects;
53 import java.util.Set;
54 import java.util.concurrent.locks.ReentrantLock;
55
56 import static java.util.concurrent.TimeUnit.MILLISECONDS;
57
58 /**
59 * A multicast datagram socket based on a datagram channel.
60 *
61 * This class overrides every public method defined by java.net.DatagramSocket
62 * and java.net.MulticastSocket. The methods in this class are defined in exactly
63 * the same order as in java.net.DatagramSocket and java.net.MulticastSocket so
64 * as to simplify tracking changes.
65 */
66 public class DatagramSocketAdaptor
67 extends MulticastSocket
68 {
69 // The channel being adapted
70 private final DatagramChannelImpl dc;
71
72 // Timeout "option" value for receives
73 private volatile int timeout;
74
75 private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
76 super(/*SocketAddress*/null);
77 this.dc = dc;
78 }
79
80 static DatagramSocket create(DatagramChannelImpl dc) {
81 try {
82 return new DatagramSocketAdaptor(dc);
83 } catch (IOException e) {
84 throw new Error(e);
85 }
86 }
87
88 private void connectInternal(SocketAddress remote) throws SocketException {
89 try {
90 dc.connect(remote, false); // skips check for already connected
91 } catch (ClosedChannelException e) {
92 // ignore
93 } catch (Exception x) {
94 Net.translateToSocketException(x);
95 }
96 }
97
98 @Override
99 public void bind(SocketAddress local) throws SocketException {
100 if (local != null) {
101 local = Net.asInetSocketAddress(local);
102 } else {
103 local = new InetSocketAddress(0);
104 }
105 try {
402 public DatagramChannel getChannel() {
403 return dc;
404 }
405
406 @Override
407 public <T> DatagramSocket setOption(SocketOption<T> name, T value) throws IOException {
408 dc.setOption(name, value);
409 return this;
410 }
411
412 @Override
413 public <T> T getOption(SocketOption<T> name) throws IOException {
414 return dc.getOption(name);
415 }
416
417 @Override
418 public Set<SocketOption<?>> supportedOptions() {
419 return dc.supportedOptions();
420 }
421
422 // -- java.net.MulticastSocket --
423
424 // used to coordinate changing TTL with the deprecated send method
425 private final ReentrantLock sendLock = new ReentrantLock();
426
427 // cached outgoing interface (for use by setInterface/getInterface)
428 private final Object outgoingInterfaceLock = new Object();
429 private NetworkInterface outgoingNetworkInterface;
430 private InetAddress outgoingInetAddress;
431
432 @Override
433 @Deprecated
434 public void setTTL(byte ttl) throws IOException {
435 setTimeToLive(Byte.toUnsignedInt(ttl));
436 }
437
438 @Override
439 public void setTimeToLive(int ttl) throws IOException {
440 sendLock.lock();
441 try {
442 setIntOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
443 } finally {
444 sendLock.unlock();
445 }
446 }
447
448 @Override
449 @Deprecated
450 public byte getTTL() throws IOException {
451 return (byte) getTimeToLive();
452 }
453
454 @Override
455 public int getTimeToLive() throws IOException {
456 sendLock.lock();
457 try {
458 return getIntOption(StandardSocketOptions.IP_MULTICAST_TTL);
459 } finally {
460 sendLock.unlock();
461 }
462 }
463
464 @Override
465 @Deprecated
466 public void joinGroup(InetAddress group) throws IOException {
467 Objects.requireNonNull(group);
468 try {
469 joinGroup(new InetSocketAddress(group, 0), null);
470 } catch (IllegalArgumentException iae) {
471 // 1-arg joinGroup does not specify IllegalArgumentException
472 throw (SocketException) new SocketException("joinGroup failed").initCause(iae);
473 }
474 }
475
476 @Override
477 @Deprecated
478 public void leaveGroup(InetAddress group) throws IOException {
479 Objects.requireNonNull(group);
480 try {
481 leaveGroup(new InetSocketAddress(group, 0), null);
482 } catch (IllegalArgumentException iae) {
483 // 1-arg leaveGroup does not specify IllegalArgumentException
484 throw (SocketException) new SocketException("leaveGroup failed").initCause(iae);
485 }
486 }
487
488 /**
489 * Checks a SocketAddress to ensure that it is a multicast address.
490 *
491 * @return the multicast group
492 * @throws IllegalArgumentException if group is null, an unsupported address
493 * type, or an unresolved address
494 * @throws SocketException if group is not a multicast address
495 */
496 private static InetAddress checkGroup(SocketAddress mcastaddr) throws SocketException {
497 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
498 throw new IllegalArgumentException("Unsupported address type");
499 InetAddress group = ((InetSocketAddress) mcastaddr).getAddress();
500 if (group == null)
501 throw new IllegalArgumentException("Unresolved address");
502 if (!group.isMulticastAddress())
503 throw new SocketException("Not a multicast address");
504 return group;
505 }
506
507 @Override
508 public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
509 InetAddress group = checkGroup(mcastaddr);
510 NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
511 if (isClosed())
512 throw new SocketException("Socket is closed");
513 synchronized (this) {
514 MembershipKey key = dc.findMembership(group, ni);
515 if (key != null) {
516 // already a member but need to check permission anyway
517 SecurityManager sm = System.getSecurityManager();
518 if (sm != null)
519 sm.checkMulticast(group);
520 throw new SocketException("Already a member of group");
521 }
522 dc.join(group, ni); // checks permission
523 }
524 }
525
526 @Override
527 public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
528 InetAddress group = checkGroup(mcastaddr);
529 NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
530 if (isClosed())
531 throw new SocketException("Socket is closed");
532 SecurityManager sm = System.getSecurityManager();
533 if (sm != null)
534 sm.checkMulticast(group);
535 synchronized (this) {
536 MembershipKey key = dc.findMembership(group, ni);
537 if (key == null)
538 throw new SocketException("Not a member of group");
539 key.drop();
540 }
541 }
542
543 @Override
544 @Deprecated
545 public void setInterface(InetAddress inf) throws SocketException {
546 if (inf == null)
547 throw new SocketException("Invalid value 'null'");
548 NetworkInterface ni = NetworkInterface.getByInetAddress(inf);
549 if (ni == null) {
550 String address = inf.getHostAddress();
551 throw new SocketException("No network interface with address " + address);
552 }
553 synchronized (outgoingInterfaceLock) {
554 // set interface and update cached values
555 setNetworkInterface(ni);
556 outgoingNetworkInterface = ni;
557 outgoingInetAddress = inf;
558 }
559 }
560
561 @Override
562 @Deprecated
563 public InetAddress getInterface() throws SocketException {
564 synchronized (outgoingInterfaceLock) {
565 NetworkInterface ni = outgoingNetworkInterface();
566 if (ni != null) {
567 if (ni.equals(outgoingNetworkInterface)) {
568 return outgoingInetAddress;
569 } else {
570 // network interface has changed so update cached values
571 PrivilegedAction<InetAddress> pa;
572 pa = () -> ni.inetAddresses().findFirst().orElse(null);
573 InetAddress ia = AccessController.doPrivileged(pa);
574 if (ia == null)
575 throw new SocketException("Network interface has no IP address");
576 outgoingNetworkInterface = ni;
577 outgoingInetAddress = ia;
578 return ia;
579 }
580 }
581 }
582
583 // no interface set
584 return anyInetAddress();
585 }
586
587 @Override
588 public void setNetworkInterface(NetworkInterface netIf) throws SocketException {
589 try {
590 setOption(StandardSocketOptions.IP_MULTICAST_IF, netIf);
591 } catch (IOException e) {
592 Net.translateToSocketException(e);
593 }
594 }
595
596 @Override
597 public NetworkInterface getNetworkInterface() throws SocketException {
598 NetworkInterface ni = outgoingNetworkInterface();
599 if (ni == null) {
600 // return NetworkInterface with index == 0 as placeholder
601 ni = anyNetworkInterface();
602 }
603 return ni;
604 }
605
606 @Override
607 @Deprecated
608 public void setLoopbackMode(boolean disable) throws SocketException {
609 boolean enable = !disable;
610 setBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP, enable);
611 }
612
613 @Override
614 @Deprecated
615 public boolean getLoopbackMode() throws SocketException {
616 boolean enabled = getBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP);
617 return !enabled;
618 }
619
620 @Override
621 @Deprecated
622 public void send(DatagramPacket p, byte ttl) throws IOException {
623 sendLock.lock();
624 try {
625 int oldValue = getTimeToLive();
626 try {
627 setTTL(ttl);
628 send(p);
629 } finally {
630 setTimeToLive(oldValue);
631 }
632 } finally {
633 sendLock.unlock();
634 }
635 }
636
637 /**
638 * Returns the outgoing NetworkInterface or null if not set.
639 */
640 private NetworkInterface outgoingNetworkInterface() throws SocketException {
641 try {
642 return getOption(StandardSocketOptions.IP_MULTICAST_IF);
643 } catch (IOException e) {
644 Net.translateToSocketException(e);
645 return null; // keep compiler happy
646 }
647 }
648
649 /**
650 * Returns the default NetworkInterface to use when joining or leaving a
651 * multicast group and a network interface is not specified.
652 * This method will return the outgoing NetworkInterface if set, otherwise
653 * the result of NetworkInterface.getDefault(), otherwise a NetworkInterface
654 * with index == 0 as a placeholder for "any network interface".
655 */
656 private NetworkInterface defaultNetworkInterface() throws SocketException {
657 NetworkInterface ni = outgoingNetworkInterface();
658 if (ni == null)
659 ni = NetworkInterfaces.getDefault(); // macOS
660 if (ni == null)
661 ni = anyNetworkInterface();
662 return ni;
663 }
664
665 /**
666 * Returns the placeholder for "any network interface", its index is 0.
667 */
668 private NetworkInterface anyNetworkInterface() {
669 InetAddress[] addrs = new InetAddress[1];
670 addrs[0] = anyInetAddress();
671 return NetworkInterfaces.newNetworkInterface(addrs[0].getHostName(), 0, addrs);
672 }
673
674 /**
675 * Returns the InetAddress representing anyLocalAddress.
676 */
677 private InetAddress anyInetAddress() {
678 return new InetSocketAddress(0).getAddress();
679 }
680
681 /**
682 * Defines static methods to get/set DatagramPacket fields and workaround
683 * DatagramPacket deficiencies.
684 */
685 private static class DatagramPackets {
686 private static final VarHandle LENGTH;
687 private static final VarHandle BUF_LENGTH;
688 static {
689 try {
690 PrivilegedExceptionAction<Lookup> pa = () ->
691 MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
692 MethodHandles.Lookup l = AccessController.doPrivileged(pa);
693 LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
694 BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
695 } catch (Exception e) {
696 throw new ExceptionInInitializerError(e);
697 }
698 }
699
700 /**
701 * Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be
702 * used at this time because it sets both the length and bufLength fields.
703 */
704 static void setLength(DatagramPacket p, int value) {
705 synchronized (p) {
706 LENGTH.set(p, value);
707 }
708 }
709
710 /**
711 * Returns the value of the DatagramPacket.bufLength field.
712 */
713 static int getBufLength(DatagramPacket p) {
714 synchronized (p) {
715 return (int) BUF_LENGTH.get(p);
716 }
717 }
718 }
719
720 /**
721 * Defines static methods to invoke non-public NetworkInterface methods.
722 */
723 private static class NetworkInterfaces {
724 static final MethodHandle GET_DEFAULT;
725 static final MethodHandle CONSTRUCTOR;
726 static {
727 try {
728 PrivilegedExceptionAction<Lookup> pa = () ->
729 MethodHandles.privateLookupIn(NetworkInterface.class, MethodHandles.lookup());
730 MethodHandles.Lookup l = AccessController.doPrivileged(pa);
731 MethodType methodType = MethodType.methodType(NetworkInterface.class);
732 GET_DEFAULT = l.findStatic(NetworkInterface.class, "getDefault", methodType);
733 methodType = MethodType.methodType(void.class, String.class, int.class, InetAddress[].class);
734 CONSTRUCTOR = l.findConstructor(NetworkInterface.class, methodType);
735 } catch (Exception e) {
736 throw new ExceptionInInitializerError(e);
737 }
738 }
739
740 /**
741 * Returns the default network interface or null.
742 */
743 static NetworkInterface getDefault() {
744 try {
745 return (NetworkInterface) GET_DEFAULT.invokeExact();
746 } catch (Throwable e) {
747 throw new InternalError(e);
748 }
749 }
750
751 /**
752 * Creates a NetworkInterface with the given name index and addresses.
753 */
754 static NetworkInterface newNetworkInterface(String name, int index, InetAddress[] addrs) {
755 try {
756 return (NetworkInterface) CONSTRUCTOR.invoke(name, index, addrs);
757 } catch (Throwable e) {
758 throw new InternalError(e);
759 }
760 }
761 }
762 }
|