| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.harmony.nio.internal; |
| |
| import java.io.FileDescriptor; |
| import java.io.IOException; |
| import java.io.InterruptedIOException; |
| import java.net.ConnectException; |
| import java.net.DatagramPacket; |
| import java.net.DatagramSocket; |
| import java.net.DatagramSocketImpl; |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| import java.net.SocketAddress; |
| import java.net.SocketException; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.AlreadyConnectedException; |
| import java.nio.channels.ClosedChannelException; |
| import java.nio.channels.DatagramChannel; |
| import java.nio.channels.IllegalBlockingModeException; |
| import java.nio.channels.NotYetConnectedException; |
| import java.nio.channels.spi.SelectorProvider; |
| |
| import org.apache.harmony.luni.net.NetUtil; |
| import org.apache.harmony.luni.net.PlainDatagramSocketImpl; |
| import org.apache.harmony.luni.platform.FileDescriptorHandler; |
| import org.apache.harmony.luni.platform.INetworkSystem; |
| import org.apache.harmony.luni.platform.Platform; |
| import org.apache.harmony.luni.util.ErrorCodeException; |
| import org.apache.harmony.nio.AddressUtil; |
| |
| /* |
| * The default implementation class of java.nio.channels.DatagramChannel. |
| */ |
| class DatagramChannelImpl extends DatagramChannel implements |
| FileDescriptorHandler { |
| |
| // The singleton to do the native network operation. |
| private static final INetworkSystem networkSystem = Platform |
| .getNetworkSystem(); |
| |
| // default timeout used to nonblocking mode. |
| private static final int DEFAULT_TIMEOUT = 1; |
| |
| private static final int ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK = -211; |
| |
| private static final byte[] stubArray = new byte[0]; |
| |
| // The fd to interact with native code |
| private FileDescriptor fd; |
| |
| // Our internal DatagramSocket. |
| private DatagramSocket socket = null; |
| |
| // The address to be connected. |
| InetSocketAddress connectAddress = null; |
| |
| // local port |
| private int localPort; |
| |
| // At first, uninitialized. |
| boolean connected = false; |
| |
| // whether the socket is bound |
| boolean isBound = false; |
| |
| private static class ReadLock {} |
| private final Object readLock = new ReadLock(); |
| |
| private static class WriteLock {} |
| private final Object writeLock = new WriteLock(); |
| |
| // used to store the trafficClass value which is simply returned |
| // as the value that was set. We also need it to pass it to methods |
| // that specify an address packets are going to be sent to |
| private int trafficClass = 0; |
| |
| /* |
| * Constructor |
| */ |
| protected DatagramChannelImpl(SelectorProvider selectorProvider) |
| throws IOException { |
| super(selectorProvider); |
| fd = new FileDescriptor(); |
| networkSystem.createDatagramSocket(fd, true); |
| } |
| |
| /* |
| * for native call |
| */ |
| @SuppressWarnings("unused") |
| private DatagramChannelImpl() { |
| super(SelectorProvider.provider()); |
| fd = new FileDescriptor(); |
| connectAddress = new InetSocketAddress(0); |
| } |
| |
| /* |
| * Getting the internal DatagramSocket If we have not the socket, we create |
| * a new one. |
| */ |
| @Override |
| synchronized public DatagramSocket socket() { |
| if (null == socket) { |
| socket = new DatagramSocketAdapter( |
| new PlainDatagramSocketImpl(fd, localPort), this); |
| } |
| return socket; |
| } |
| |
| /** |
| * Answer the local address from the IP stack. This method should not be |
| * called directly as it does not check the security policy. |
| * |
| * @return InetAddress the local address to which the socket is bound. |
| * @see DatagramSocket |
| */ |
| InetAddress getLocalAddress() { |
| return networkSystem.getSocketLocalAddress(fd, NetUtil |
| .preferIPv6Addresses()); |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#isConnected() |
| */ |
| @Override |
| synchronized public boolean isConnected() { |
| return connected; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#connect(java.net.SocketAddress) |
| */ |
| @Override |
| synchronized public DatagramChannel connect(SocketAddress address) |
| throws IOException { |
| // must open |
| checkOpen(); |
| // status must be un-connected. |
| if (connected) { |
| throw new IllegalStateException(); |
| } |
| |
| // check the address |
| InetSocketAddress inetSocketAddress = SocketChannelImpl |
| .validateAddress(address); |
| |
| // security check |
| SecurityManager sm = System.getSecurityManager(); |
| if (null != sm) { |
| if (inetSocketAddress.getAddress().isMulticastAddress()) { |
| sm.checkMulticast(inetSocketAddress.getAddress()); |
| } else { |
| sm.checkConnect(inetSocketAddress.getAddress().getHostName(), |
| inetSocketAddress.getPort()); |
| } |
| } |
| |
| try { |
| begin(); |
| networkSystem.connectDatagram(fd, inetSocketAddress.getPort(), |
| trafficClass, inetSocketAddress.getAddress()); |
| } catch (ConnectException e) { |
| // ConnectException means connect fail, not exception |
| } finally { |
| end(true); |
| } |
| |
| // set the connected address. |
| connectAddress = inetSocketAddress; |
| connected = true; |
| isBound = true; |
| return this; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#disconnect() |
| */ |
| @Override |
| synchronized public DatagramChannel disconnect() throws IOException { |
| if (!isConnected() || !isOpen()) { |
| return this; |
| } |
| connected = false; |
| connectAddress = null; |
| networkSystem.disconnectDatagram(fd); |
| if (null != socket) { |
| socket.disconnect(); |
| } |
| return this; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#receive(java.nio.ByteBuffer) |
| */ |
| @Override |
| public SocketAddress receive(ByteBuffer target) throws IOException { |
| // must not null and not readonly |
| checkWritable(target); |
| // must open |
| checkOpen(); |
| |
| if (!isBound) { |
| return null; |
| } |
| |
| SocketAddress retAddr = null; |
| try { |
| begin(); |
| |
| // receive real data packet, (not peek) |
| synchronized (readLock) { |
| boolean loop = isBlocking(); |
| if (!target.isDirect()) { |
| retAddr = receiveImpl(target, loop); |
| } else { |
| retAddr = receiveDirectImpl(target, loop); |
| } |
| } |
| } catch (InterruptedIOException e) { |
| // this line used in Linux |
| return null; |
| } finally { |
| end(null != retAddr); |
| } |
| return retAddr; |
| } |
| |
| private SocketAddress receiveImpl(ByteBuffer target, boolean loop) |
| throws IOException { |
| SocketAddress retAddr = null; |
| DatagramPacket receivePacket; |
| int oldposition = target.position(); |
| int received = 0; |
| if (target.hasArray()) { |
| receivePacket = new DatagramPacket(target.array(), target |
| .position() |
| + target.arrayOffset(), target.remaining()); |
| } else { |
| receivePacket = new DatagramPacket(new byte[target.remaining()], |
| target.remaining()); |
| } |
| do { |
| if (isConnected()) { |
| received = networkSystem.recvConnectedDatagram(fd, |
| receivePacket, receivePacket.getData(), receivePacket |
| .getOffset(), receivePacket.getLength(), |
| isBlocking() ? 0 : DEFAULT_TIMEOUT, false); |
| } else { |
| received = networkSystem.receiveDatagram(fd, receivePacket, |
| receivePacket.getData(), receivePacket.getOffset(), |
| receivePacket.getLength(), isBlocking() ? 0 |
| : DEFAULT_TIMEOUT, false); |
| } |
| |
| // security check |
| SecurityManager sm = System.getSecurityManager(); |
| if (!isConnected() && null != sm) { |
| try { |
| sm.checkAccept(receivePacket.getAddress().getHostAddress(), |
| receivePacket.getPort()); |
| } catch (SecurityException e) { |
| // do discard the datagram packet |
| receivePacket = null; |
| } |
| } |
| if (null != receivePacket && null != receivePacket.getAddress()) { |
| |
| if (received > 0) { |
| if (target.hasArray()) { |
| target.position(oldposition + received); |
| } else { |
| // copy the data of received packet |
| target.put(receivePacket.getData(), 0, received); |
| } |
| } |
| retAddr = receivePacket.getSocketAddress(); |
| break; |
| } |
| } while (loop); |
| return retAddr; |
| } |
| |
| private SocketAddress receiveDirectImpl(ByteBuffer target, boolean loop) |
| throws IOException { |
| SocketAddress retAddr = null; |
| DatagramPacket receivePacket = new DatagramPacket(stubArray, 0); |
| int oldposition = target.position(); |
| int received = 0; |
| do { |
| long address = AddressUtil.getDirectBufferAddress(target); |
| if (isConnected()) { |
| received = networkSystem.recvConnectedDatagramDirect(fd, |
| receivePacket, address, target.position(), target |
| .remaining(), isBlocking() ? 0 |
| : DEFAULT_TIMEOUT, false); |
| } else { |
| received = networkSystem.receiveDatagramDirect(fd, |
| receivePacket, address, target.position(), target |
| .remaining(), isBlocking() ? 0 |
| : DEFAULT_TIMEOUT, false); |
| } |
| |
| // security check |
| SecurityManager sm = System.getSecurityManager(); |
| if (!isConnected() && null != sm) { |
| try { |
| sm.checkAccept(receivePacket.getAddress().getHostAddress(), |
| receivePacket.getPort()); |
| } catch (SecurityException e) { |
| // do discard the datagram packet |
| receivePacket = null; |
| } |
| } |
| if (null != receivePacket && null != receivePacket.getAddress()) { |
| // copy the data of received packet |
| if (received > 0) { |
| target.position(oldposition + received); |
| } |
| retAddr = receivePacket.getSocketAddress(); |
| break; |
| } |
| } while (loop); |
| return retAddr; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#send(java.nio.ByteBuffer, |
| * java.net.SocketAddress) |
| */ |
| @Override |
| public int send(ByteBuffer source, SocketAddress socketAddress) |
| throws IOException { |
| // must not null |
| checkNotNull(source); |
| // must open |
| checkOpen(); |
| |
| // transfer socketAddress |
| InetSocketAddress isa = (InetSocketAddress) socketAddress; |
| if (null == isa.getAddress()) { |
| throw new IOException(); |
| } |
| |
| if (isConnected()) { |
| if (!connectAddress.equals(isa)) { |
| throw new IllegalArgumentException(); |
| } |
| } else { |
| // not connected, check security |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| if (isa.getAddress().isMulticastAddress()) { |
| sm.checkMulticast(isa.getAddress()); |
| } else { |
| sm.checkConnect(isa.getAddress().getHostAddress(), isa |
| .getPort()); |
| } |
| } |
| } |
| |
| // the return value. |
| int sendCount = 0; |
| try { |
| begin(); |
| byte[] array = null; |
| int length = source.remaining(); |
| int oldposition = source.position(); |
| int start = oldposition; |
| if (source.isDirect()) { |
| synchronized (writeLock) { |
| long data_address = AddressUtil |
| .getDirectBufferAddress(source); |
| sendCount = networkSystem.sendDatagramDirect(fd, |
| data_address, start, length, isa.getPort(), false, |
| trafficClass, isa.getAddress()); |
| } |
| } else { |
| if (source.hasArray()) { |
| array = source.array(); |
| start += source.arrayOffset(); |
| } else { |
| array = new byte[length]; |
| source.get(array); |
| start = 0; |
| } |
| synchronized (writeLock) { |
| sendCount = networkSystem.sendDatagram(fd, array, start, |
| length, isa.getPort(), false, trafficClass, isa |
| .getAddress()); |
| } |
| } |
| source.position(oldposition + sendCount); |
| return sendCount; |
| } finally { |
| end(sendCount >= 0); |
| } |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#read(java.nio.ByteBuffer) |
| */ |
| @Override |
| public int read(ByteBuffer target) throws IOException { |
| if (null == target) { |
| throw new NullPointerException(); |
| } |
| // status must be open and connected |
| checkOpenConnected(); |
| // target buffer must be not null and not readonly |
| checkWritable(target); |
| |
| if (!target.hasRemaining()) { |
| return 0; |
| } |
| |
| int readCount = 0; |
| if (target.isDirect() || target.hasArray()) { |
| readCount = readImpl(target); |
| if (readCount > 0) { |
| target.position(target.position() + readCount); |
| } |
| |
| } else { |
| byte[] readArray = new byte[target.remaining()]; |
| ByteBuffer readBuffer = ByteBuffer.wrap(readArray); |
| readCount = readImpl(readBuffer); |
| if (readCount > 0) { |
| target.put(readArray, 0, readCount); |
| } |
| } |
| return readCount; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#read(java.nio.ByteBuffer[], int, |
| * int) |
| */ |
| @Override |
| public long read(ByteBuffer[] targets, int offset, int length) |
| throws IOException { |
| if (length < 0 || offset < 0 |
| || (long) length + (long) offset > targets.length) { |
| throw new IndexOutOfBoundsException(); |
| } |
| |
| // status must be open and connected |
| checkOpenConnected(); |
| |
| int totalCount = 0; |
| for (int val = offset; val < length; val++) { |
| // target buffer must be not null and not readonly |
| checkWritable(targets[val]); |
| totalCount += targets[val].remaining(); |
| } |
| |
| // read data to readBuffer, and then transfer data from readBuffer to |
| // targets. |
| ByteBuffer readBuffer = ByteBuffer.allocate(totalCount); |
| int readCount; |
| readCount = readImpl(readBuffer); |
| int left = readCount; |
| int index = offset; |
| // transfer data from readBuffer to targets |
| byte[] readArray = readBuffer.array(); |
| while (left > 0) { |
| int putLength = Math.min(targets[index].remaining(), left); |
| targets[index].put(readArray, readCount - left, putLength); |
| index++; |
| left -= putLength; |
| } |
| return readCount; |
| } |
| |
| /* |
| * read from channel, and store the result in the target. |
| */ |
| private int readImpl(ByteBuffer readBuffer) throws IOException { |
| synchronized (readLock) { |
| int readCount = 0; |
| try { |
| begin(); |
| // timeout == 0 means block read. |
| // DEFAULT_TIMEOUT is used in non-block mode. |
| int timeout = isBlocking() ? 0 : DEFAULT_TIMEOUT; |
| int start = readBuffer.position(); |
| int length = readBuffer.remaining(); |
| if (readBuffer.isDirect()) { |
| long address = AddressUtil |
| .getDirectBufferAddress(readBuffer); |
| if (isConnected()) { |
| readCount = networkSystem.recvConnectedDatagramDirect( |
| fd, null, address, start, length, timeout, |
| false); |
| } else { |
| readCount = networkSystem.receiveDatagramDirect(fd, |
| null, address, start, length, timeout, false); |
| } |
| } else { |
| // the target is assured to have array. |
| byte[] target = readBuffer.array(); |
| start += readBuffer.arrayOffset(); |
| if (isConnected()) { |
| readCount = networkSystem.recvConnectedDatagram(fd, |
| null, target, start, length, timeout, false); |
| } else { |
| readCount = networkSystem.receiveDatagram(fd, null, |
| target, start, length, timeout, false); |
| } |
| } |
| return readCount; |
| } catch (InterruptedIOException e) { |
| // InterruptedIOException will be thrown when timeout. |
| return 0; |
| } finally { |
| end(readCount > 0); |
| } |
| } |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#write(java.nio.ByteBuffer) |
| */ |
| @Override |
| public int write(ByteBuffer source) throws IOException { |
| // source buffer must be not null |
| checkNotNull(source); |
| // status must be open and connected |
| checkOpenConnected(); |
| // return immediately if source is full |
| if (!source.hasRemaining()) { |
| return 0; |
| } |
| |
| ByteBuffer writeBuffer = null; |
| byte[] writeArray = null; |
| int oldposition = source.position(); |
| int result; |
| if (source.isDirect() || source.hasArray()) { |
| writeBuffer = source; |
| } else { |
| writeArray = new byte[source.remaining()]; |
| source.get(writeArray); |
| writeBuffer = ByteBuffer.wrap(writeArray); |
| } |
| result = writeImpl(writeBuffer); |
| if (result > 0) { |
| source.position(oldposition + result); |
| } |
| return result; |
| } |
| |
| /** |
| * @see java.nio.channels.DatagramChannel#write(java.nio.ByteBuffer[], int, |
| * int) |
| */ |
| @Override |
| public long write(ByteBuffer[] sources, int offset, int length) |
| throws IOException { |
| if (length < 0 || offset < 0 |
| || (long) length + (long) offset > sources.length) { |
| throw new IndexOutOfBoundsException(); |
| } |
| |
| // status must be open and connected |
| checkOpenConnected(); |
| int count = calculateByteBufferArray(sources, offset, length); |
| if (0 == count) { |
| return 0; |
| } |
| ByteBuffer writeBuf = ByteBuffer.allocate(count); |
| for (int val = offset; val < length + offset; val++) { |
| ByteBuffer source = sources[val]; |
| int oldPosition = source.position(); |
| writeBuf.put(source); |
| source.position(oldPosition); |
| } |
| writeBuf.flip(); |
| int result = writeImpl(writeBuf); |
| int val = offset; |
| int written = result; |
| while (result > 0) { |
| ByteBuffer source = sources[val]; |
| int gap = Math.min(result, source.remaining()); |
| source.position(source.position() + gap); |
| val++; |
| result -= gap; |
| } |
| return written; |
| } |
| |
| /* |
| * Write the source. Return the count of bytes written. |
| */ |
| private int writeImpl(ByteBuffer buf) throws IOException { |
| synchronized (writeLock) { |
| int result = 0; |
| try { |
| begin(); |
| int length = buf.remaining(); |
| int start = buf.position(); |
| |
| if (buf.isDirect()) { |
| long address = AddressUtil.getDirectBufferAddress(buf); |
| result = networkSystem.sendConnectedDatagramDirect(fd, |
| address, start, length, isBound); |
| } else { |
| // buf is assured to have array. |
| start += buf.arrayOffset(); |
| result = networkSystem.sendConnectedDatagram(fd, buf |
| .array(), start, length, isBound); |
| } |
| return result; |
| } catch (SocketException e) { |
| if (e.getCause() instanceof ErrorCodeException) { |
| if (ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK == ((ErrorCodeException) e |
| .getCause()).getErrorCode()) { |
| return result; |
| } |
| } |
| throw e; |
| } finally { |
| end(result > 0); |
| } |
| } |
| } |
| |
| /* |
| * Do really closing action here. |
| */ |
| @Override |
| synchronized protected void implCloseSelectableChannel() throws IOException { |
| connected = false; |
| if (null != socket && !socket.isClosed()) { |
| socket.close(); |
| } else { |
| networkSystem.socketClose(fd); |
| } |
| } |
| |
| /** |
| * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean) |
| */ |
| @Override |
| @SuppressWarnings("unused") |
| protected void implConfigureBlocking(boolean blockingMode) |
| throws IOException { |
| // Do nothing here. For real read/write operation in nonblocking mode, |
| // it uses select system call. Whether a channel is blocking can be |
| // decided by isBlocking() method. |
| } |
| |
| /* |
| * Status check, must be open. |
| */ |
| private void checkOpen() throws IOException { |
| if (!isOpen()) { |
| throw new ClosedChannelException(); |
| } |
| } |
| |
| /* |
| * Status check, must be open and connected, for read and write. |
| */ |
| private void checkOpenConnected() throws IOException { |
| checkOpen(); |
| if (!isConnected()) { |
| throw new NotYetConnectedException(); |
| } |
| } |
| |
| /* |
| * Buffer check, must not null |
| */ |
| private void checkNotNull(ByteBuffer source) { |
| if (null == source) { |
| throw new NullPointerException(); |
| } |
| } |
| |
| /* |
| * Buffer check, must not null and not read only buffer, for read and |
| * receive. |
| */ |
| private void checkWritable(ByteBuffer target) { |
| // including checking of NPE. |
| if (target.isReadOnly()) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /* |
| * Get the fd for internal use. |
| */ |
| public FileDescriptor getFD() { |
| return fd; |
| } |
| |
| private int calculateByteBufferArray(ByteBuffer[] sources, int offset, |
| int length) { |
| int sum = 0; |
| for (int val = offset; val < offset + length; val++) { |
| sum += sources[val].remaining(); |
| } |
| return sum; |
| } |
| |
| /* |
| * The adapter class of DatagramSocket |
| */ |
| private static class DatagramSocketAdapter extends DatagramSocket { |
| |
| /* |
| * The internal datagramChannelImpl. |
| */ |
| private DatagramChannelImpl channelImpl; |
| |
| /* |
| * Constructor initialize the datagramSocketImpl and datagramChannelImpl |
| */ |
| DatagramSocketAdapter(DatagramSocketImpl socketimpl, |
| DatagramChannelImpl channelImpl) { |
| super(socketimpl); |
| this.channelImpl = channelImpl; |
| } |
| |
| /* |
| * Get the internal datagramChannelImpl |
| */ |
| @Override |
| public DatagramChannel getChannel() { |
| return channelImpl; |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#isBound() |
| */ |
| @Override |
| public boolean isBound() { |
| return channelImpl.isBound; |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#isConnected() |
| */ |
| @Override |
| public boolean isConnected() { |
| return channelImpl.isConnected(); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#getInetAddress() |
| */ |
| @Override |
| public InetAddress getInetAddress() { |
| if (null == channelImpl.connectAddress) { |
| return null; |
| } |
| return channelImpl.connectAddress.getAddress(); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#getLocalAddress() |
| */ |
| @Override |
| public InetAddress getLocalAddress() { |
| return channelImpl.getLocalAddress(); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#getPort() |
| */ |
| @Override |
| public int getPort() { |
| if (null == channelImpl.connectAddress) { |
| return -1; |
| } |
| return channelImpl.connectAddress.getPort(); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#bind(java.net.SocketAddress) |
| */ |
| @Override |
| public void bind(SocketAddress localAddr) throws SocketException { |
| if (channelImpl.isConnected()) { |
| throw new AlreadyConnectedException(); |
| } |
| super.bind(localAddr); |
| channelImpl.isBound = true; |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#receive(java.net.DatagramPacket) |
| */ |
| @Override |
| public void receive(DatagramPacket packet) throws IOException { |
| if (!channelImpl.isBlocking()) { |
| throw new IllegalBlockingModeException(); |
| } |
| super.receive(packet); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#send(java.net.DatagramPacket) |
| */ |
| @Override |
| public void send(DatagramPacket packet) throws IOException { |
| if (!channelImpl.isBlocking()) { |
| throw new IllegalBlockingModeException(); |
| } |
| super.send(packet); |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#close() |
| */ |
| @Override |
| public void close() { |
| synchronized (channelImpl) { |
| if (channelImpl.isOpen()) { |
| try { |
| channelImpl.close(); |
| } catch (IOException e) { |
| // Ignore |
| } |
| } |
| super.close(); |
| } |
| } |
| |
| /** |
| * @see java.net.DatagramSocket#disconnect() |
| */ |
| @Override |
| public void disconnect() { |
| try { |
| channelImpl.disconnect(); |
| } catch (IOException e) { |
| // Ignore |
| } |
| super.disconnect(); |
| } |
| } |
| } |