Path: blob/master/src/java.base/share/classes/java/net/NetMulticastSocket.java
41152 views
/*1* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.net;2627import java.io.IOException;28import java.io.UncheckedIOException;29import java.nio.channels.DatagramChannel;30import java.security.AccessController;31import java.security.PrivilegedExceptionAction;32import java.util.Enumeration;33import java.util.Objects;34import java.util.Set;35import java.util.Collections;3637/**38* A multicast datagram socket that delegates socket operations to a39* {@link DatagramSocketImpl}.40*41* This class overrides every public method defined by {@link DatagramSocket}42* and {@link MulticastSocket}.43*/44final class NetMulticastSocket extends MulticastSocket {45/**46* Various states of this socket.47*/48private boolean bound = false;49private boolean closed = false;50private volatile boolean created;51private final Object closeLock = new Object();5253/*54* The implementation of this DatagramSocket.55*/56private final DatagramSocketImpl impl;5758/**59* Are we using an older DatagramSocketImpl?60*/61private final boolean oldImpl;6263/**64* Set when a socket is ST_CONNECTED until we are certain65* that any packets which might have been received prior66* to calling connect() but not read by the application67* have been read. During this time we check the source68* address of all packets received to be sure they are from69* the connected destination. Other packets are read but70* silently dropped.71*/72private boolean explicitFilter = false;73private int bytesLeftToFilter;74/*75* Connection state:76* ST_NOT_CONNECTED = socket not connected77* ST_CONNECTED = socket connected78* ST_CONNECTED_NO_IMPL = socket connected but not at impl level79*/80static final int ST_NOT_CONNECTED = 0;81static final int ST_CONNECTED = 1;82static final int ST_CONNECTED_NO_IMPL = 2;8384int connectState = ST_NOT_CONNECTED;8586/*87* Connected address & port88*/89InetAddress connectedAddress = null;90int connectedPort = -1;9192/**93* This constructor is also used by {@link DatagramSocket#DatagramSocket(DatagramSocketImpl)}.94* @param impl The impl used in this instance.95*/96NetMulticastSocket(DatagramSocketImpl impl) {97super((MulticastSocket) null);98this.impl = Objects.requireNonNull(impl);99this.oldImpl = checkOldImpl(impl);100}101102/**103* Connects this socket to a remote socket address (IP address + port number).104* Binds socket if not already bound.105*106* @param address The remote address.107* @param port The remote port108* @throws SocketException if binding the socket fails.109*/110private synchronized void connectInternal(InetAddress address, int port) throws SocketException {111if (port < 0 || port > 0xFFFF) {112throw new IllegalArgumentException("connect: " + port);113}114if (address == null) {115throw new IllegalArgumentException("connect: null address");116}117checkAddress(address, "connect");118if (isClosed())119return;120@SuppressWarnings("removal")121SecurityManager security = System.getSecurityManager();122if (security != null) {123if (address.isMulticastAddress()) {124security.checkMulticast(address);125} else {126security.checkConnect(address.getHostAddress(), port);127security.checkAccept(address.getHostAddress(), port);128}129}130131if (port == 0) {132throw new SocketException("Can't connect to port 0");133}134if (!isBound())135bind(new InetSocketAddress(0));136137// old impls do not support connect/disconnect138if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&139((AbstractPlainDatagramSocketImpl) impl).nativeConnectDisabled())) {140connectState = ST_CONNECTED_NO_IMPL;141} else {142try {143getImpl().connect(address, port);144145// socket is now connected by the impl146connectState = ST_CONNECTED;147// Do we need to filter some packets?148int avail = getImpl().dataAvailable();149if (avail == -1) {150throw new SocketException();151}152explicitFilter = avail > 0;153if (explicitFilter) {154bytesLeftToFilter = getReceiveBufferSize();155}156} catch (SocketException se) {157158// connection will be emulated by DatagramSocket159connectState = ST_CONNECTED_NO_IMPL;160}161}162163connectedAddress = address;164connectedPort = port;165}166167/**168* Return true if the given DatagramSocketImpl is an "old" impl. An old impl169* is one that doesn't implement the abstract methods added in Java SE 1.4.170*/171@SuppressWarnings("removal")172private static boolean checkOldImpl(DatagramSocketImpl impl) {173// DatagramSocketImpl.peekData() is a protected method, therefore we need to use174// getDeclaredMethod, therefore we need permission to access the member175try {176AccessController.doPrivileged(177new PrivilegedExceptionAction<>() {178public Void run() throws NoSuchMethodException {179Class<?>[] cl = new Class<?>[1];180cl[0] = DatagramPacket.class;181impl.getClass().getDeclaredMethod("peekData", cl);182return null;183}184});185return false;186} catch (java.security.PrivilegedActionException e) {187return true;188}189}190191/**192* Return the {@code DatagramSocketImpl} attached to this socket,193* creating the socket if not already created.194*195* @return the {@code DatagramSocketImpl} attached to that196* DatagramSocket197* @throws SocketException if creating the socket fails198* @since 1.4199*/200final DatagramSocketImpl getImpl() throws SocketException {201if (!created) {202synchronized (this) {203if (!created) {204impl.create();205created = true;206}207}208}209return impl;210}211212@Override213public synchronized void bind(SocketAddress addr) throws SocketException {214if (isClosed())215throw new SocketException("Socket is closed");216if (isBound())217throw new SocketException("already bound");218if (addr == null)219addr = new InetSocketAddress(0);220if (!(addr instanceof InetSocketAddress epoint))221throw new IllegalArgumentException("Unsupported address type!");222if (epoint.isUnresolved())223throw new SocketException("Unresolved address");224InetAddress iaddr = epoint.getAddress();225int port = epoint.getPort();226checkAddress(iaddr, "bind");227@SuppressWarnings("removal")228SecurityManager sec = System.getSecurityManager();229if (sec != null) {230sec.checkListen(port);231}232try {233getImpl().bind(port, iaddr);234} catch (SocketException e) {235getImpl().close();236throw e;237}238bound = true;239}240241static void checkAddress(InetAddress addr, String op) {242if (addr == null) {243return;244}245if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {246throw new IllegalArgumentException(op + ": invalid address type");247}248}249250@Override251public void connect(InetAddress address, int port) {252try {253connectInternal(address, port);254} catch (SocketException se) {255throw new UncheckedIOException("connect failed", se);256}257}258259@Override260public void connect(SocketAddress addr) throws SocketException {261if (addr == null)262throw new IllegalArgumentException("Address can't be null");263if (!(addr instanceof InetSocketAddress epoint))264throw new IllegalArgumentException("Unsupported address type");265if (epoint.isUnresolved())266throw new SocketException("Unresolved address");267connectInternal(epoint.getAddress(), epoint.getPort());268}269270@Override271public void disconnect() {272synchronized (this) {273if (isClosed())274return;275if (connectState == ST_CONNECTED) {276impl.disconnect();277}278connectedAddress = null;279connectedPort = -1;280connectState = ST_NOT_CONNECTED;281explicitFilter = false;282}283}284285@Override286public boolean isBound() {287return bound;288}289290@Override291public boolean isConnected() {292return connectState != ST_NOT_CONNECTED;293}294295@Override296public InetAddress getInetAddress() {297return connectedAddress;298}299300@Override301public int getPort() {302return connectedPort;303}304305@Override306public SocketAddress getRemoteSocketAddress() {307if (!isConnected())308return null;309return new InetSocketAddress(getInetAddress(), getPort());310}311312@Override313public SocketAddress getLocalSocketAddress() {314if (isClosed())315return null;316if (!isBound())317return null;318return new InetSocketAddress(getLocalAddress(), getLocalPort());319}320321@Override322public void send(DatagramPacket p) throws IOException {323synchronized (p) {324if (isClosed())325throw new SocketException("Socket is closed");326InetAddress packetAddress = p.getAddress();327int packetPort = p.getPort();328checkAddress(packetAddress, "send");329if (connectState == ST_NOT_CONNECTED) {330if (packetAddress == null) {331throw new IllegalArgumentException("Address not set");332}333if (packetPort < 0 || packetPort > 0xFFFF)334throw new IllegalArgumentException("port out of range: " + packetPort);335// check the address is ok with the security manager on every send.336@SuppressWarnings("removal")337SecurityManager security = System.getSecurityManager();338339// The reason you want to synchronize on datagram packet340// is because you don't want an applet to change the address341// while you are trying to send the packet for example342// after the security check but before the send.343if (security != null) {344if (packetAddress.isMulticastAddress()) {345security.checkMulticast(packetAddress);346} else {347security.checkConnect(packetAddress.getHostAddress(),348packetPort);349}350}351if (packetPort == 0) {352throw new SocketException("Can't send to port 0");353}354} else {355// we're connected356if (packetAddress == null) {357p.setAddress(connectedAddress);358p.setPort(connectedPort);359} else if ((!packetAddress.equals(connectedAddress)) ||360packetPort != connectedPort) {361throw new IllegalArgumentException("connected address " +362"and packet address" +363" differ");364}365}366// Check whether the socket is bound367if (!isBound())368bind(new InetSocketAddress(0));369// call the method to send370getImpl().send(p);371}372}373374@Override375public synchronized void receive(DatagramPacket p) throws IOException {376synchronized (p) {377if (!isBound())378bind(new InetSocketAddress(0));379if (connectState == ST_NOT_CONNECTED) {380// check the address is ok with the security manager before every recv.381@SuppressWarnings("removal")382SecurityManager security = System.getSecurityManager();383if (security != null) {384while (true) {385String peekAd = null;386int peekPort = 0;387// peek at the packet to see who it is from.388if (!oldImpl) {389// We can use the new peekData() API390DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);391peekPort = getImpl().peekData(peekPacket);392peekAd = peekPacket.getAddress().getHostAddress();393} else {394InetAddress adr = new InetAddress();395peekPort = getImpl().peek(adr);396peekAd = adr.getHostAddress();397}398try {399security.checkAccept(peekAd, peekPort);400// security check succeeded - so now break401// and recv the packet.402break;403} catch (SecurityException se) {404// Throw away the offending packet by consuming405// it in a tmp buffer.406DatagramPacket tmp = new DatagramPacket(new byte[1], 1);407getImpl().receive(tmp);408409// silently discard the offending packet410// and continue: unknown/malicious411// entities on nets should not make412// runtime throw security exception and413// disrupt the applet by sending random414// datagram packets.415continue;416}417} // end of while418}419}420DatagramPacket tmp = null;421if ((connectState == ST_CONNECTED_NO_IMPL) || explicitFilter) {422// We have to do the filtering the old fashioned way since423// the native impl doesn't support connect or the connect424// via the impl failed, or .. "explicitFilter" may be set when425// a socket is connected via the impl, for a period of time426// when packets from other sources might be queued on socket.427boolean stop = false;428while (!stop) {429InetAddress peekAddress = null;430int peekPort = -1;431// peek at the packet to see who it is from.432if (!oldImpl) {433// We can use the new peekData() API434DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);435peekPort = getImpl().peekData(peekPacket);436peekAddress = peekPacket.getAddress();437} else {438// this api only works for IPv4439peekAddress = new InetAddress();440peekPort = getImpl().peek(peekAddress);441}442if ((!connectedAddress.equals(peekAddress)) ||443(connectedPort != peekPort)) {444// throw the packet away and silently continue445tmp = new DatagramPacket(446new byte[1024], 1024);447getImpl().receive(tmp);448if (explicitFilter) {449if (checkFiltering(tmp)) {450stop = true;451}452}453} else {454stop = true;455}456}457}458// If the security check succeeds, or the datagram is459// connected then receive the packet460getImpl().receive(p);461if (explicitFilter && tmp == null) {462// packet was not filtered, account for it here463checkFiltering(p);464}465}466}467468private boolean checkFiltering(DatagramPacket p) throws SocketException {469bytesLeftToFilter -= p.getLength();470if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) {471explicitFilter = false;472return true;473}474return false;475}476477@Override478public InetAddress getLocalAddress() {479if (isClosed())480return null;481InetAddress in;482try {483in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);484if (in.isAnyLocalAddress()) {485in = InetAddress.anyLocalAddress();486}487@SuppressWarnings("removal")488SecurityManager s = System.getSecurityManager();489if (s != null) {490s.checkConnect(in.getHostAddress(), -1);491}492} catch (Exception e) {493in = InetAddress.anyLocalAddress(); // "0.0.0.0"494}495return in;496}497498@Override499public int getLocalPort() {500if (isClosed())501return -1;502try {503return getImpl().getLocalPort();504} catch (Exception e) {505return 0;506}507}508509@Override510public synchronized void setSoTimeout(int timeout) throws SocketException {511if (isClosed())512throw new SocketException("Socket is closed");513if (timeout < 0)514throw new IllegalArgumentException("timeout < 0");515getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);516}517518@Override519public synchronized int getSoTimeout() throws SocketException {520if (isClosed())521throw new SocketException("Socket is closed");522if (getImpl() == null)523return 0;524Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);525/* extra type safety */526if (o instanceof Integer) {527return ((Integer) o).intValue();528} else {529return 0;530}531}532533@Override534public synchronized void setSendBufferSize(int size) throws SocketException {535if (!(size > 0)) {536throw new IllegalArgumentException("negative send size");537}538if (isClosed())539throw new SocketException("Socket is closed");540getImpl().setOption(SocketOptions.SO_SNDBUF, size);541}542543@Override544public synchronized int getSendBufferSize() throws SocketException {545if (isClosed())546throw new SocketException("Socket is closed");547int result = 0;548Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);549if (o instanceof Integer) {550result = ((Integer) o).intValue();551}552return result;553}554555@Override556public synchronized void setReceiveBufferSize(int size) throws SocketException {557if (size <= 0) {558throw new IllegalArgumentException("invalid receive size");559}560if (isClosed())561throw new SocketException("Socket is closed");562getImpl().setOption(SocketOptions.SO_RCVBUF, size);563}564565@Override566public synchronized int getReceiveBufferSize() throws SocketException {567if (isClosed())568throw new SocketException("Socket is closed");569int result = 0;570Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);571if (o instanceof Integer) {572result = ((Integer) o).intValue();573}574return result;575}576577@Override578public synchronized void setReuseAddress(boolean on) throws SocketException {579if (isClosed())580throw new SocketException("Socket is closed");581// Integer instead of Boolean for compatibility with older DatagramSocketImpl582if (oldImpl)583getImpl().setOption(SocketOptions.SO_REUSEADDR, on ? -1 : 0);584else585getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));586}587588@Override589public synchronized boolean getReuseAddress() throws SocketException {590if (isClosed())591throw new SocketException("Socket is closed");592Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);593return ((Boolean) o).booleanValue();594}595596@Override597public synchronized void setBroadcast(boolean on) throws SocketException {598if (isClosed())599throw new SocketException("Socket is closed");600getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));601}602603@Override604public synchronized boolean getBroadcast() throws SocketException {605if (isClosed())606throw new SocketException("Socket is closed");607return ((Boolean) (getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();608}609610@Override611public synchronized void setTrafficClass(int tc) throws SocketException {612if (tc < 0 || tc > 255)613throw new IllegalArgumentException("tc is not in range 0 -- 255");614615if (isClosed())616throw new SocketException("Socket is closed");617try {618getImpl().setOption(SocketOptions.IP_TOS, tc);619} catch (SocketException se) {620// not supported if socket already connected621// Solaris returns error in such cases622if (!isConnected())623throw se;624}625}626627@Override628public synchronized int getTrafficClass() throws SocketException {629if (isClosed())630throw new SocketException("Socket is closed");631return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();632}633634@Override635public void close() {636synchronized (closeLock) {637if (isClosed())638return;639impl.close();640closed = true;641}642}643644@Override645public boolean isClosed() {646synchronized (closeLock) {647return closed;648}649}650651@Override652public <T> DatagramSocket setOption(SocketOption<T> name, T value)653throws IOException654{655Objects.requireNonNull(name);656if (isClosed())657throw new SocketException("Socket is closed");658getImpl().setOption(name, value);659return this;660}661662@Override663public <T> T getOption(SocketOption<T> name) throws IOException {664Objects.requireNonNull(name);665if (isClosed())666throw new SocketException("Socket is closed");667return getImpl().getOption(name);668}669670private volatile Set<SocketOption<?>> options;671private final Object optionsLock = new Object();672673@Override674public Set<SocketOption<?>> supportedOptions() {675Set<SocketOption<?>> options = this.options;676if (options != null)677return options;678synchronized (optionsLock) {679options = this.options;680if (options != null) {681return options;682}683try {684DatagramSocketImpl impl = getImpl();685options = Collections.unmodifiableSet(impl.supportedOptions());686} catch (IOException e) {687options = Collections.emptySet();688}689return this.options = options;690}691}692693// Multicast socket support694695/**696* Used on some platforms to record if an outgoing interface697* has been set for this socket.698*/699private boolean interfaceSet;700701/**702* The lock on the socket's TTL. This is for set/getTTL and703* send(packet,ttl).704*/705private final Object ttlLock = new Object();706707/**708* The lock on the socket's interface - used by setInterface709* and getInterface710*/711private final Object infLock = new Object();712713/**714* The "last" interface set by setInterface on this MulticastSocket715*/716private InetAddress infAddress = null;717718@Deprecated719@Override720public void setTTL(byte ttl) throws IOException {721if (isClosed())722throw new SocketException("Socket is closed");723getImpl().setTTL(ttl);724}725726@Override727public void setTimeToLive(int ttl) throws IOException {728if (ttl < 0 || ttl > 255) {729throw new IllegalArgumentException("ttl out of range");730}731if (isClosed())732throw new SocketException("Socket is closed");733getImpl().setTimeToLive(ttl);734}735736@Deprecated737@Override738public byte getTTL() throws IOException {739if (isClosed())740throw new SocketException("Socket is closed");741return getImpl().getTTL();742}743744@Override745public int getTimeToLive() throws IOException {746if (isClosed())747throw new SocketException("Socket is closed");748return getImpl().getTimeToLive();749}750751@Override752@Deprecated753public void joinGroup(InetAddress mcastaddr) throws IOException {754if (isClosed()) {755throw new SocketException("Socket is closed");756}757758checkAddress(mcastaddr, "joinGroup");759@SuppressWarnings("removal")760SecurityManager security = System.getSecurityManager();761if (security != null) {762security.checkMulticast(mcastaddr);763}764765if (!mcastaddr.isMulticastAddress()) {766throw new SocketException("Not a multicast address");767}768769/**770* required for some platforms where it's not possible to join771* a group without setting the interface first.772*/773NetworkInterface defaultInterface = NetworkInterface.getDefault();774775if (!interfaceSet && defaultInterface != null) {776setNetworkInterface(defaultInterface);777}778779getImpl().join(mcastaddr);780}781782@Override783@Deprecated784public void leaveGroup(InetAddress mcastaddr) throws IOException {785if (isClosed()) {786throw new SocketException("Socket is closed");787}788789checkAddress(mcastaddr, "leaveGroup");790@SuppressWarnings("removal")791SecurityManager security = System.getSecurityManager();792if (security != null) {793security.checkMulticast(mcastaddr);794}795796if (!mcastaddr.isMulticastAddress()) {797throw new SocketException("Not a multicast address");798}799800getImpl().leave(mcastaddr);801}802803@Override804public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)805throws IOException {806if (isClosed())807throw new SocketException("Socket is closed");808809if (!(mcastaddr instanceof InetSocketAddress addr))810throw new IllegalArgumentException("Unsupported address type");811812if (oldImpl)813throw new UnsupportedOperationException();814815checkAddress(addr.getAddress(), "joinGroup");816@SuppressWarnings("removal")817SecurityManager security = System.getSecurityManager();818if (security != null) {819security.checkMulticast(addr.getAddress());820}821822if (!addr.getAddress().isMulticastAddress()) {823throw new SocketException("Not a multicast address");824}825826getImpl().joinGroup(mcastaddr, netIf);827}828829@Override830public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)831throws IOException {832if (isClosed())833throw new SocketException("Socket is closed");834835if (!(mcastaddr instanceof InetSocketAddress addr))836throw new IllegalArgumentException("Unsupported address type");837838if (oldImpl)839throw new UnsupportedOperationException();840841checkAddress(addr.getAddress(), "leaveGroup");842@SuppressWarnings("removal")843SecurityManager security = System.getSecurityManager();844if (security != null) {845security.checkMulticast(addr.getAddress());846}847848if (!addr.getAddress().isMulticastAddress()) {849throw new SocketException("Not a multicast address");850}851852getImpl().leaveGroup(mcastaddr, netIf);853}854855@Override856@Deprecated857public void setInterface(InetAddress inf) throws SocketException {858if (isClosed()) {859throw new SocketException("Socket is closed");860}861checkAddress(inf, "setInterface");862synchronized (infLock) {863getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);864infAddress = inf;865interfaceSet = true;866}867}868869@Override870@Deprecated871public InetAddress getInterface() throws SocketException {872if (isClosed()) {873throw new SocketException("Socket is closed");874}875synchronized (infLock) {876InetAddress ia =877(InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);878879/**880* No previous setInterface or interface can be881* set using setNetworkInterface882*/883if (infAddress == null) {884return ia;885}886887/**888* Same interface set with setInterface?889*/890if (ia.equals(infAddress)) {891return ia;892}893894/**895* Different InetAddress from what we set with setInterface896* so enumerate the current interface to see if the897* address set by setInterface is bound to this interface.898*/899try {900NetworkInterface ni = NetworkInterface.getByInetAddress(ia);901Enumeration<InetAddress> addrs = ni.getInetAddresses();902while (addrs.hasMoreElements()) {903InetAddress addr = addrs.nextElement();904if (addr.equals(infAddress)) {905return infAddress;906}907}908909/**910* No match so reset infAddress to indicate that the911* interface has changed via means912*/913infAddress = null;914return ia;915} catch (Exception e) {916return ia;917}918}919}920921@Override922public void setNetworkInterface(NetworkInterface netIf)923throws SocketException {924925synchronized (infLock) {926getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);927infAddress = null;928interfaceSet = true;929}930}931932@Override933public NetworkInterface getNetworkInterface() throws SocketException {934NetworkInterface ni935= (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);936if (ni == null) {937InetAddress[] addrs = new InetAddress[1];938addrs[0] = InetAddress.anyLocalAddress();939return new NetworkInterface(addrs[0].getHostName(), 0, addrs);940} else {941return ni;942}943}944945@Override946@Deprecated947public void setLoopbackMode(boolean disable) throws SocketException {948getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));949}950951@Override952@Deprecated953public boolean getLoopbackMode() throws SocketException {954return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();955}956957@SuppressWarnings("removal")958@Deprecated959@Override960public void send(DatagramPacket p, byte ttl)961throws IOException {962if (isClosed())963throw new SocketException("Socket is closed");964synchronized(ttlLock) {965synchronized(p) {966InetAddress packetAddress = p.getAddress();967checkAddress(packetAddress, "send");968if (connectState == NetMulticastSocket.ST_NOT_CONNECTED) {969if (packetAddress == null) {970throw new IllegalArgumentException("Address not set");971}972// Security manager makes sure that the multicast address973// is allowed one and that the ttl used is less974// than the allowed maxttl.975SecurityManager security = System.getSecurityManager();976if (security != null) {977if (packetAddress.isMulticastAddress()) {978security.checkMulticast(packetAddress, ttl);979} else {980security.checkConnect(packetAddress.getHostAddress(),981p.getPort());982}983}984} else {985// we're connected986if (packetAddress == null) {987p.setAddress(connectedAddress);988p.setPort(connectedPort);989} else if ((!packetAddress.equals(connectedAddress)) ||990p.getPort() != connectedPort) {991throw new IllegalArgumentException("connected address and packet address" +992" differ");993}994}995byte dttl = getTTL();996try {997if (ttl != dttl) {998// set the ttl999getImpl().setTTL(ttl);1000}1001if (p.getPort() == 0) {1002throw new SocketException("Can't send to port 0");1003}1004// call the datagram method to send1005getImpl().send(p);1006} finally {1007// set it back to default1008if (ttl != dttl) {1009getImpl().setTTL(dttl);1010}1011}1012} // synch p1013} //synch ttl1014} //method1015}101610171018