001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.nio.internal;
019:
020: import java.io.FileDescriptor;
021: import java.io.IOException;
022: import java.io.InterruptedIOException;
023: import java.net.ConnectException;
024: import java.net.DatagramPacket;
025: import java.net.DatagramSocket;
026: import java.net.DatagramSocketImpl;
027: import java.net.InetAddress;
028: import java.net.InetSocketAddress;
029: import java.net.SocketAddress;
030: import java.net.SocketException;
031: import java.nio.ByteBuffer;
032: import java.nio.channels.AlreadyConnectedException;
033: import java.nio.channels.ClosedChannelException;
034: import java.nio.channels.DatagramChannel;
035: import java.nio.channels.IllegalBlockingModeException;
036: import java.nio.channels.NotYetConnectedException;
037: import java.nio.channels.spi.SelectorProvider;
038:
039: import org.apache.harmony.luni.net.NetUtil;
040: import org.apache.harmony.luni.net.SocketImplProvider;
041: import org.apache.harmony.luni.platform.FileDescriptorHandler;
042: import org.apache.harmony.luni.platform.INetworkSystem;
043: import org.apache.harmony.luni.platform.Platform;
044: import org.apache.harmony.luni.util.ErrorCodeException;
045: import org.apache.harmony.nio.AddressUtil;
046:
047: /*
048: * The default implementation class of java.nio.channels.DatagramChannel.
049: */
050: class DatagramChannelImpl extends DatagramChannel implements
051: FileDescriptorHandler {
052:
053: // The singleton to do the native network operation.
054: private static final INetworkSystem networkSystem = Platform
055: .getNetworkSystem();
056:
057: // default timeout used to nonblocking mode.
058: private static final int DEFAULT_TIMEOUT = 1;
059:
060: private static final int ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK = -211;
061:
062: private static final byte[] stubArray = new byte[0];
063:
064: // The fd to interact with native code
065: private FileDescriptor fd;
066:
067: // Our internal DatagramSocket.
068: private DatagramSocket socket = null;
069:
070: // The address to be connected.
071: InetSocketAddress connectAddress = null;
072:
073: // local port
074: private int localPort;
075:
076: // At first, uninitialized.
077: boolean connected = false;
078:
079: // whether the socket is bound
080: boolean isBound = false;
081:
082: private static class ReadLock {
083: }
084:
085: private final Object readLock = new ReadLock();
086:
087: private static class WriteLock {
088: }
089:
090: private final Object writeLock = new WriteLock();
091:
092: // used to store the trafficClass value which is simply returned
093: // as the value that was set. We also need it to pass it to methods
094: // that specify an address packets are going to be sent to
095: private int trafficClass = 0;
096:
097: /*
098: * Constructor
099: */
100: protected DatagramChannelImpl(SelectorProvider selectorProvider)
101: throws IOException {
102: super (selectorProvider);
103: fd = new FileDescriptor();
104: networkSystem.createDatagramSocket(fd, true);
105: }
106:
107: /*
108: * for native call
109: */
110: @SuppressWarnings("unused")
111: private DatagramChannelImpl() {
112: super (SelectorProvider.provider());
113: fd = new FileDescriptor();
114: connectAddress = new InetSocketAddress(0);
115: }
116:
117: /*
118: * Getting the internal DatagramSocket If we have not the socket, we create
119: * a new one.
120: */
121: @Override
122: synchronized public DatagramSocket socket() {
123: if (null == socket) {
124: socket = new DatagramSocketAdapter(SocketImplProvider
125: .getDatagramSocketImpl(fd, localPort), this );
126: }
127: return socket;
128: }
129:
130: /**
131: * Answer the local address from the IP stack. This method should not be
132: * called directly as it does not check the security policy.
133: *
134: * @return InetAddress the local address to which the socket is bound.
135: * @see DatagramSocket
136: */
137: InetAddress getLocalAddress() {
138: return networkSystem.getSocketLocalAddress(fd, NetUtil
139: .preferIPv6Addresses());
140: }
141:
142: /**
143: * @see java.nio.channels.DatagramChannel#isConnected()
144: */
145: @Override
146: synchronized public boolean isConnected() {
147: return connected;
148: }
149:
150: /**
151: * @see java.nio.channels.DatagramChannel#connect(java.net.SocketAddress)
152: */
153: @Override
154: synchronized public DatagramChannel connect(SocketAddress address)
155: throws IOException {
156: // must open
157: checkOpen();
158: // status must be un-connected.
159: if (connected) {
160: throw new IllegalStateException();
161: }
162:
163: // check the address
164: InetSocketAddress inetSocketAddress = SocketChannelImpl
165: .validateAddress(address);
166:
167: // security check
168: SecurityManager sm = System.getSecurityManager();
169: if (null != sm) {
170: if (inetSocketAddress.getAddress().isMulticastAddress()) {
171: sm.checkMulticast(inetSocketAddress.getAddress());
172: } else {
173: sm.checkConnect(inetSocketAddress.getAddress()
174: .getHostName(), inetSocketAddress.getPort());
175: }
176: }
177:
178: try {
179: begin();
180: networkSystem.connectDatagram(fd, inetSocketAddress
181: .getPort(), trafficClass, inetSocketAddress
182: .getAddress());
183: } catch (ConnectException e) {
184: // ConnectException means connect fail, not exception
185: } finally {
186: end(true);
187: }
188:
189: // set the connected address.
190: connectAddress = inetSocketAddress;
191: connected = true;
192: isBound = true;
193: return this ;
194: }
195:
196: /**
197: * @see java.nio.channels.DatagramChannel#disconnect()
198: */
199: @Override
200: synchronized public DatagramChannel disconnect() throws IOException {
201: if (!isConnected() || !isOpen()) {
202: return this ;
203: }
204: connected = false;
205: connectAddress = null;
206: networkSystem.disconnectDatagram(fd);
207: if (null != socket) {
208: socket.disconnect();
209: }
210: return this ;
211: }
212:
213: /**
214: * @see java.nio.channels.DatagramChannel#receive(java.nio.ByteBuffer)
215: */
216: @Override
217: public SocketAddress receive(ByteBuffer target) throws IOException {
218: // must not null and not readonly
219: checkWritable(target);
220: // must open
221: checkOpen();
222:
223: if (!isBound) {
224: return null;
225: }
226:
227: SocketAddress retAddr = null;
228: try {
229: begin();
230:
231: // receive real data packet, (not peek)
232: synchronized (readLock) {
233: boolean loop = isBlocking();
234: if (!target.isDirect()) {
235: retAddr = receiveImpl(target, loop);
236: } else {
237: retAddr = receiveDirectImpl(target, loop);
238: }
239: }
240: } catch (InterruptedIOException e) {
241: // this line used in Linux
242: return null;
243: } finally {
244: end(null != retAddr);
245: }
246: return retAddr;
247: }
248:
249: private SocketAddress receiveImpl(ByteBuffer target, boolean loop)
250: throws IOException {
251: SocketAddress retAddr = null;
252: DatagramPacket receivePacket;
253: int oldposition = target.position();
254: int received = 0;
255: if (target.hasArray()) {
256: receivePacket = new DatagramPacket(target.array(), target
257: .position()
258: + target.arrayOffset(), target.remaining());
259: } else {
260: receivePacket = new DatagramPacket(new byte[target
261: .remaining()], target.remaining());
262: }
263: do {
264: if (isConnected()) {
265: received = networkSystem.recvConnectedDatagram(fd,
266: receivePacket, receivePacket.getData(),
267: receivePacket.getOffset(), receivePacket
268: .getLength(), isBlocking() ? 0
269: : DEFAULT_TIMEOUT, false);
270: } else {
271: received = networkSystem.receiveDatagram(fd,
272: receivePacket, receivePacket.getData(),
273: receivePacket.getOffset(), receivePacket
274: .getLength(), isBlocking() ? 0
275: : DEFAULT_TIMEOUT, false);
276: }
277:
278: // security check
279: SecurityManager sm = System.getSecurityManager();
280: if (!isConnected() && null != sm) {
281: try {
282: sm.checkAccept(receivePacket.getAddress()
283: .getHostAddress(), receivePacket.getPort());
284: } catch (SecurityException e) {
285: // do discard the datagram packet
286: receivePacket = null;
287: }
288: }
289: if (null != receivePacket
290: && null != receivePacket.getAddress()) {
291:
292: if (received > 0) {
293: if (target.hasArray()) {
294: target.position(oldposition + received);
295: } else {
296: // copy the data of received packet
297: target
298: .put(receivePacket.getData(), 0,
299: received);
300: }
301: }
302: retAddr = receivePacket.getSocketAddress();
303: break;
304: }
305: } while (loop);
306: return retAddr;
307: }
308:
309: private SocketAddress receiveDirectImpl(ByteBuffer target,
310: boolean loop) throws IOException {
311: SocketAddress retAddr = null;
312: DatagramPacket receivePacket = new DatagramPacket(stubArray, 0);
313: int oldposition = target.position();
314: int received = 0;
315: do {
316: long address = AddressUtil.getDirectBufferAddress(target);
317: if (isConnected()) {
318: received = networkSystem.recvConnectedDatagramDirect(
319: fd, receivePacket, address, target.position(),
320: target.remaining(), isBlocking() ? 0
321: : DEFAULT_TIMEOUT, false);
322: } else {
323: received = networkSystem.receiveDatagramDirect(fd,
324: receivePacket, address, target.position(),
325: target.remaining(), isBlocking() ? 0
326: : DEFAULT_TIMEOUT, false);
327: }
328:
329: // security check
330: SecurityManager sm = System.getSecurityManager();
331: if (!isConnected() && null != sm) {
332: try {
333: sm.checkAccept(receivePacket.getAddress()
334: .getHostAddress(), receivePacket.getPort());
335: } catch (SecurityException e) {
336: // do discard the datagram packet
337: receivePacket = null;
338: }
339: }
340: if (null != receivePacket
341: && null != receivePacket.getAddress()) {
342: // copy the data of received packet
343: if (received > 0) {
344: target.position(oldposition + received);
345: }
346: retAddr = receivePacket.getSocketAddress();
347: break;
348: }
349: } while (loop);
350: return retAddr;
351: }
352:
353: /**
354: * @see java.nio.channels.DatagramChannel#send(java.nio.ByteBuffer,
355: * java.net.SocketAddress)
356: */
357: @Override
358: public int send(ByteBuffer source, SocketAddress socketAddress)
359: throws IOException {
360: // must not null
361: checkNotNull(source);
362: // must open
363: checkOpen();
364:
365: // transfer socketAddress
366: InetSocketAddress isa = (InetSocketAddress) socketAddress;
367: if (null == isa.getAddress()) {
368: throw new IOException();
369: }
370:
371: if (isConnected()) {
372: if (!connectAddress.equals(isa)) {
373: throw new IllegalArgumentException();
374: }
375: } else {
376: // not connected, check security
377: SecurityManager sm = System.getSecurityManager();
378: if (sm != null) {
379: if (isa.getAddress().isMulticastAddress()) {
380: sm.checkMulticast(isa.getAddress());
381: } else {
382: sm.checkConnect(isa.getAddress().getHostAddress(),
383: isa.getPort());
384: }
385: }
386: }
387:
388: // the return value.
389: int sendCount = 0;
390: try {
391: begin();
392: byte[] array = null;
393: int length = source.remaining();
394: int oldposition = source.position();
395: int start = oldposition;
396: if (source.isDirect()) {
397: synchronized (writeLock) {
398: long data_address = AddressUtil
399: .getDirectBufferAddress(source);
400: sendCount = networkSystem.sendDatagramDirect(fd,
401: data_address, start, length, isa.getPort(),
402: false, trafficClass, isa.getAddress());
403: }
404: } else {
405: if (source.hasArray()) {
406: array = source.array();
407: start += source.arrayOffset();
408: } else {
409: array = new byte[length];
410: source.get(array);
411: start = 0;
412: }
413: synchronized (writeLock) {
414: sendCount = networkSystem.sendDatagram(fd, array,
415: start, length, isa.getPort(), false,
416: trafficClass, isa.getAddress());
417: }
418: }
419: source.position(oldposition + sendCount);
420: return sendCount;
421: } finally {
422: end(sendCount >= 0);
423: }
424: }
425:
426: /**
427: * @see java.nio.channels.DatagramChannel#read(java.nio.ByteBuffer)
428: */
429: @Override
430: public int read(ByteBuffer target) throws IOException {
431: if (null == target) {
432: throw new NullPointerException();
433: }
434: // status must be open and connected
435: checkOpenConnected();
436: // target buffer must be not null and not readonly
437: checkWritable(target);
438:
439: if (!target.hasRemaining()) {
440: return 0;
441: }
442:
443: int readCount = 0;
444: if (target.isDirect() || target.hasArray()) {
445: readCount = readImpl(target);
446: if (readCount > 0) {
447: target.position(target.position() + readCount);
448: }
449:
450: } else {
451: byte[] readArray = new byte[target.remaining()];
452: ByteBuffer readBuffer = ByteBuffer.wrap(readArray);
453: readCount = readImpl(readBuffer);
454: if (readCount > 0) {
455: target.put(readArray, 0, readCount);
456: }
457: }
458: return readCount;
459: }
460:
461: /**
462: * @see java.nio.channels.DatagramChannel#read(java.nio.ByteBuffer[], int,
463: * int)
464: */
465: @Override
466: public long read(ByteBuffer[] targets, int offset, int length)
467: throws IOException {
468: if (length < 0 || offset < 0
469: || (long) length + (long) offset > targets.length) {
470: throw new IndexOutOfBoundsException();
471: }
472:
473: // status must be open and connected
474: checkOpenConnected();
475:
476: int totalCount = 0;
477: for (int val = offset; val < length; val++) {
478: // target buffer must be not null and not readonly
479: checkWritable(targets[val]);
480: totalCount += targets[val].remaining();
481: }
482:
483: // read data to readBuffer, and then transfer data from readBuffer to
484: // targets.
485: ByteBuffer readBuffer = ByteBuffer.allocate(totalCount);
486: int readCount;
487: readCount = readImpl(readBuffer);
488: int left = readCount;
489: int index = offset;
490: // transfer data from readBuffer to targets
491: byte[] readArray = readBuffer.array();
492: while (left > 0) {
493: int putLength = Math.min(targets[index].remaining(), left);
494: targets[index].put(readArray, readCount - left, putLength);
495: index++;
496: left -= putLength;
497: }
498: return readCount;
499: }
500:
501: /*
502: * read from channel, and store the result in the target.
503: */
504: private int readImpl(ByteBuffer readBuffer) throws IOException {
505: synchronized (readLock) {
506: int readCount = 0;
507: try {
508: begin();
509: // timeout == 0 means block read.
510: // DEFAULT_TIMEOUT is used in non-block mode.
511: int timeout = isBlocking() ? 0 : DEFAULT_TIMEOUT;
512: int start = readBuffer.position();
513: int length = readBuffer.remaining();
514: if (readBuffer.isDirect()) {
515: long address = AddressUtil
516: .getDirectBufferAddress(readBuffer);
517: if (isConnected()) {
518: readCount = networkSystem
519: .recvConnectedDatagramDirect(fd, null,
520: address, start, length,
521: timeout, false);
522: } else {
523: readCount = networkSystem
524: .receiveDatagramDirect(fd, null,
525: address, start, length,
526: timeout, false);
527: }
528: } else {
529: // the target is assured to have array.
530: byte[] target = readBuffer.array();
531: start += readBuffer.arrayOffset();
532: if (isConnected()) {
533: readCount = networkSystem
534: .recvConnectedDatagram(fd, null,
535: target, start, length, timeout,
536: false);
537: } else {
538: readCount = networkSystem.receiveDatagram(fd,
539: null, target, start, length, timeout,
540: false);
541: }
542: }
543: return readCount;
544: } catch (InterruptedIOException e) {
545: // InterruptedIOException will be thrown when timeout.
546: return 0;
547: } finally {
548: end(readCount > 0);
549: }
550: }
551: }
552:
553: /**
554: * @see java.nio.channels.DatagramChannel#write(java.nio.ByteBuffer)
555: */
556: @Override
557: public int write(ByteBuffer source) throws IOException {
558: // source buffer must be not null
559: checkNotNull(source);
560: // status must be open and connected
561: checkOpenConnected();
562: // return immediately if source is full
563: if (!source.hasRemaining()) {
564: return 0;
565: }
566:
567: ByteBuffer writeBuffer = null;
568: byte[] writeArray = null;
569: int oldposition = source.position();
570: int result;
571: if (source.isDirect() || source.hasArray()) {
572: writeBuffer = source;
573: } else {
574: writeArray = new byte[source.remaining()];
575: source.get(writeArray);
576: writeBuffer = ByteBuffer.wrap(writeArray);
577: }
578: result = writeImpl(writeBuffer);
579: if (result > 0) {
580: source.position(oldposition + result);
581: }
582: return result;
583: }
584:
585: /**
586: * @see java.nio.channels.DatagramChannel#write(java.nio.ByteBuffer[], int,
587: * int)
588: */
589: @Override
590: public long write(ByteBuffer[] sources, int offset, int length)
591: throws IOException {
592: if (length < 0 || offset < 0
593: || (long) length + (long) offset > sources.length) {
594: throw new IndexOutOfBoundsException();
595: }
596:
597: // status must be open and connected
598: checkOpenConnected();
599: int count = calculateByteBufferArray(sources, offset, length);
600: if (0 == count) {
601: return 0;
602: }
603: ByteBuffer writeBuf = ByteBuffer.allocate(count);
604: for (int val = offset; val < length + offset; val++) {
605: ByteBuffer source = sources[val];
606: int oldPosition = source.position();
607: writeBuf.put(source);
608: source.position(oldPosition);
609: }
610: writeBuf.flip();
611: int result = writeImpl(writeBuf);
612: int val = offset;
613: int written = result;
614: while (result > 0) {
615: ByteBuffer source = sources[val];
616: int gap = Math.min(result, source.remaining());
617: source.position(source.position() + gap);
618: val++;
619: result -= gap;
620: }
621: return written;
622: }
623:
624: /*
625: * Write the source. Return the count of bytes written.
626: */
627: private int writeImpl(ByteBuffer buf) throws IOException {
628: synchronized (writeLock) {
629: int result = 0;
630: try {
631: begin();
632: int length = buf.remaining();
633: int start = buf.position();
634:
635: if (buf.isDirect()) {
636: long address = AddressUtil
637: .getDirectBufferAddress(buf);
638: result = networkSystem.sendConnectedDatagramDirect(
639: fd, address, start, length, isBound);
640: } else {
641: // buf is assured to have array.
642: start += buf.arrayOffset();
643: result = networkSystem.sendConnectedDatagram(fd,
644: buf.array(), start, length, isBound);
645: }
646: return result;
647: } catch (SocketException e) {
648: if (e.getCause() instanceof ErrorCodeException) {
649: if (ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK == ((ErrorCodeException) e
650: .getCause()).getErrorCode()) {
651: return result;
652: }
653: }
654: throw e;
655: } finally {
656: end(result > 0);
657: }
658: }
659: }
660:
661: /*
662: * Do really closing action here.
663: */
664: @Override
665: synchronized protected void implCloseSelectableChannel()
666: throws IOException {
667: connected = false;
668: if (null != socket && !socket.isClosed()) {
669: socket.close();
670: } else {
671: networkSystem.socketClose(fd);
672: }
673: }
674:
675: /**
676: * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean)
677: */
678: @Override
679: @SuppressWarnings("unused")
680: protected void implConfigureBlocking(boolean blockingMode)
681: throws IOException {
682: // Do nothing here. For real read/write operation in nonblocking mode,
683: // it uses select system call. Whether a channel is blocking can be
684: // decided by isBlocking() method.
685: }
686:
687: /*
688: * Status check, must be open.
689: */
690: private void checkOpen() throws IOException {
691: if (!isOpen()) {
692: throw new ClosedChannelException();
693: }
694: }
695:
696: /*
697: * Status check, must be open and connected, for read and write.
698: */
699: private void checkOpenConnected() throws IOException {
700: checkOpen();
701: if (!isConnected()) {
702: throw new NotYetConnectedException();
703: }
704: }
705:
706: /*
707: * Buffer check, must not null
708: */
709: private void checkNotNull(ByteBuffer source) {
710: if (null == source) {
711: throw new NullPointerException();
712: }
713: }
714:
715: /*
716: * Buffer check, must not null and not read only buffer, for read and
717: * receive.
718: */
719: private void checkWritable(ByteBuffer target) {
720: // including checking of NPE.
721: if (target.isReadOnly()) {
722: throw new IllegalArgumentException();
723: }
724: }
725:
726: /*
727: * Get the fd for internal use.
728: */
729: public FileDescriptor getFD() {
730: return fd;
731: }
732:
733: private int calculateByteBufferArray(ByteBuffer[] sources,
734: int offset, int length) {
735: int sum = 0;
736: for (int val = offset; val < offset + length; val++) {
737: sum += sources[val].remaining();
738: }
739: return sum;
740: }
741:
742: /*
743: * The adapter class of DatagramSocket
744: */
745: private static class DatagramSocketAdapter extends DatagramSocket {
746:
747: /*
748: * The internal datagramChannelImpl.
749: */
750: private DatagramChannelImpl channelImpl;
751:
752: /*
753: * Constructor initialize the datagramSocketImpl and datagramChannelImpl
754: */
755: DatagramSocketAdapter(DatagramSocketImpl socketimpl,
756: DatagramChannelImpl channelImpl) {
757: super (socketimpl);
758: this .channelImpl = channelImpl;
759: }
760:
761: /*
762: * Get the internal datagramChannelImpl
763: */
764: @Override
765: public DatagramChannel getChannel() {
766: return channelImpl;
767: }
768:
769: /**
770: * @see java.net.DatagramSocket#isBound()
771: */
772: @Override
773: public boolean isBound() {
774: return channelImpl.isBound;
775: }
776:
777: /**
778: * @see java.net.DatagramSocket#isConnected()
779: */
780: @Override
781: public boolean isConnected() {
782: return channelImpl.isConnected();
783: }
784:
785: /**
786: * @see java.net.DatagramSocket#getInetAddress()
787: */
788: @Override
789: public InetAddress getInetAddress() {
790: if (null == channelImpl.connectAddress) {
791: return null;
792: }
793: return channelImpl.connectAddress.getAddress();
794: }
795:
796: /**
797: * @see java.net.DatagramSocket#getLocalAddress()
798: */
799: @Override
800: public InetAddress getLocalAddress() {
801: return channelImpl.getLocalAddress();
802: }
803:
804: /**
805: * @see java.net.DatagramSocket#getPort()
806: */
807: @Override
808: public int getPort() {
809: if (null == channelImpl.connectAddress) {
810: return -1;
811: }
812: return channelImpl.connectAddress.getPort();
813: }
814:
815: /**
816: * @see java.net.DatagramSocket#bind(java.net.SocketAddress)
817: */
818: @Override
819: public void bind(SocketAddress localAddr)
820: throws SocketException {
821: if (channelImpl.isConnected()) {
822: throw new AlreadyConnectedException();
823: }
824: super .bind(localAddr);
825: channelImpl.isBound = true;
826: }
827:
828: /**
829: * @see java.net.DatagramSocket#receive(java.net.DatagramPacket)
830: */
831: @Override
832: public void receive(DatagramPacket packet) throws IOException {
833: if (!channelImpl.isBlocking()) {
834: throw new IllegalBlockingModeException();
835: }
836: super .receive(packet);
837: }
838:
839: /**
840: * @see java.net.DatagramSocket#send(java.net.DatagramPacket)
841: */
842: @Override
843: public void send(DatagramPacket packet) throws IOException {
844: if (!channelImpl.isBlocking()) {
845: throw new IllegalBlockingModeException();
846: }
847: super .send(packet);
848: }
849:
850: /**
851: * @see java.net.DatagramSocket#close()
852: */
853: @Override
854: public void close() {
855: synchronized (channelImpl) {
856: if (channelImpl.isOpen()) {
857: try {
858: channelImpl.close();
859: } catch (IOException e) {
860: // Ignore
861: }
862: }
863: super .close();
864: }
865: }
866:
867: /**
868: * @see java.net.DatagramSocket#disconnect()
869: */
870: @Override
871: public void disconnect() {
872: try {
873: channelImpl.disconnect();
874: } catch (IOException e) {
875: // Ignore
876: }
877: super.disconnect();
878: }
879: }
880: }
|