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 java.net;
019:
020: import java.io.IOException;
021: import java.nio.channels.DatagramChannel;
022:
023: import org.apache.harmony.luni.net.SocketImplProvider;
024: import org.apache.harmony.luni.platform.Platform;
025:
026: import org.apache.harmony.luni.util.Msg;
027:
028: /**
029: * This class models a socket for sending & receiving datagram packets.
030: *
031: * @see DatagramPacket
032: */
033: public class DatagramSocket {
034:
035: DatagramSocketImpl impl;
036:
037: InetAddress address;
038:
039: int port = -1;
040:
041: static DatagramSocketImplFactory factory;
042:
043: boolean isBound = false;
044:
045: private boolean isConnected = false;
046:
047: private boolean isClosed = false;
048:
049: private static class Lock {
050: }
051:
052: static {
053: Platform.getNetworkSystem().oneTimeInitialization(true);
054: }
055:
056: private Object lock = new Lock();
057:
058: /**
059: * Constructs a datagram socket, bound to any available port on the
060: * localhost.
061: *
062: * @throws SocketException
063: * if a problem occurs creating or binding the socket
064: */
065: public DatagramSocket() throws SocketException {
066: this (0);
067: }
068:
069: /**
070: * Answers a datagram socket, bound to the nominated port on the localhost.
071: *
072: * @param aPort
073: * the port to bind on the localhost
074: *
075: * @throws SocketException
076: * if a problem occurs creating or binding the socket
077: */
078: public DatagramSocket(int aPort) throws SocketException {
079: super ();
080: checkListen(aPort);
081: createSocket(aPort, InetAddress.ANY);
082: }
083:
084: /**
085: * Constructs a datagram socket, bound to the nominated localhost/port.
086: *
087: * @param aPort
088: * the port on the localhost to bind
089: * @param addr
090: * the address on the multihomed localhost to bind
091: *
092: * @throws SocketException
093: * if a problem occurs creating or binding the socket
094: */
095: public DatagramSocket(int aPort, InetAddress addr)
096: throws SocketException {
097: super ();
098: checkListen(aPort);
099: createSocket(aPort, null == addr ? InetAddress.ANY : addr);
100: }
101:
102: /**
103: * Sent prior to attempting to bind the socket, check that the port is
104: * within the valid port range and verify with the security manager that the
105: * port may be bound by the current context.
106: *
107: * @param aPort
108: * the port on the localhost that is to be bound
109: */
110: void checkListen(int aPort) {
111: if (aPort < 0 || aPort > 65535) {
112: throw new IllegalArgumentException(Msg.getString(
113: "K0325", aPort)); //$NON-NLS-1$
114: }
115: SecurityManager security = System.getSecurityManager();
116: if (security != null) {
117: security.checkListen(aPort);
118: }
119: }
120:
121: /**
122: * Close the socket.
123: */
124: // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is
125: // noted as not being synchronized.
126: public void close() {
127: isClosed = true;
128: impl.close();
129: }
130:
131: /**
132: * Connect the datagram socket to a remote host and port. The host and port
133: * are validated, thereafter the only validation on send() and receive() is
134: * that the packet address/port matches the connected target.
135: *
136: * @param anAddress
137: * the target address
138: * @param aPort
139: * the target port
140: */
141: public void connect(InetAddress anAddress, int aPort) {
142: if (anAddress == null || aPort < 0 || aPort > 65535) {
143: throw new IllegalArgumentException(Msg.getString("K0032")); //$NON-NLS-1$
144: }
145:
146: synchronized (lock) {
147: if (isClosed()) {
148: return;
149: }
150: try {
151: checkClosedAndBind(true);
152: } catch (SocketException e) {
153: // Ignored
154: }
155:
156: SecurityManager security = System.getSecurityManager();
157: if (security != null) {
158: if (anAddress.isMulticastAddress()) {
159: security.checkMulticast(anAddress);
160: } else {
161: security.checkConnect(anAddress.getHostName(),
162: aPort);
163: }
164: }
165:
166: try {
167: impl.connect(anAddress, aPort);
168: } catch (SocketException e) {
169: // not connected at the native level just do what we did before
170: }
171: address = anAddress;
172: port = aPort;
173: isConnected = true;
174: }
175: }
176:
177: /**
178: * 'Disconnect' the datagram socket from a remote host and port. This method
179: * may be called on an unconnected socket.
180: */
181: public void disconnect() {
182: if (isClosed() || !isConnected()) {
183: return;
184: }
185: impl.disconnect();
186: address = null;
187: port = -1;
188: isConnected = false;
189: }
190:
191: synchronized void createSocket(int aPort, InetAddress addr)
192: throws SocketException {
193: impl = factory != null ? factory.createDatagramSocketImpl()
194: : SocketImplProvider.getDatagramSocketImpl();
195: impl.create();
196: try {
197: impl.bind(aPort, addr);
198: isBound = true;
199: } catch (SocketException e) {
200: close();
201: throw e;
202: }
203: }
204:
205: /**
206: * Returns an {@link InetAddress} instance representing the address this
207: * socket has connected to.
208: *
209: * @return if this socket is connected, the address it is connected to. A
210: * <code>null</code> return signifies no connection has been made.
211: */
212: public InetAddress getInetAddress() {
213: return address;
214: }
215:
216: /**
217: * Returns an {@link InetAddress} instance representing the <i>local</i>
218: * address this socket is bound to.
219: *
220: * @return the local address to which the socket is bound
221: */
222: public InetAddress getLocalAddress() {
223: if (isClosed()) {
224: return null;
225: }
226: if (!isBound()) {
227: return InetAddress.ANY;
228: }
229: InetAddress anAddr = impl.getLocalAddress();
230: try {
231: SecurityManager security = System.getSecurityManager();
232: if (security != null) {
233: security.checkConnect(anAddr.getHostName(), -1);
234: }
235: } catch (SecurityException e) {
236: return InetAddress.ANY;
237: }
238: return anAddr;
239: }
240:
241: /**
242: * Answer the local port to which the socket is bound.
243: *
244: * @return int local port to which the socket is bound
245: */
246: public int getLocalPort() {
247: if (isClosed()) {
248: return -1;
249: }
250: if (!isBound()) {
251: return 0;
252: }
253: return impl.getLocalPort();
254: }
255:
256: /**
257: * Returns the number of the remote port this socket is connected to.
258: *
259: * @return int the remote port number that this socket has connected to. A
260: * return of <code>-1</code> indicates that there is no connection
261: * in place.
262: */
263: public int getPort() {
264: return port;
265: }
266:
267: /**
268: * Answer the socket receive buffer size (SO_RCVBUF).
269: *
270: * @return int socket receive buffer size
271: *
272: * @exception SocketException
273: * when an error occurs
274: */
275: public synchronized int getReceiveBufferSize()
276: throws SocketException {
277: checkClosedAndBind(false);
278: return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF))
279: .intValue();
280: }
281:
282: /**
283: * Answer the socket send buffer size (SO_SNDBUF).
284: *
285: * @return int socket send buffer size
286: *
287: * @exception SocketException
288: * when an error occurs
289: */
290: public synchronized int getSendBufferSize() throws SocketException {
291: checkClosedAndBind(false);
292: return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF))
293: .intValue();
294: }
295:
296: /**
297: * Answer the socket receive timeout (SO_RCVTIMEOUT), in milliseconds. Zero
298: * implies the timeout is disabled.
299: *
300: * @return int socket receive timeout
301: *
302: * @exception SocketException
303: * when an error occurs
304: */
305: public synchronized int getSoTimeout() throws SocketException {
306: checkClosedAndBind(false);
307: return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT))
308: .intValue();
309: }
310:
311: /**
312: * Receive on this socket into the packet argument. This method blocks until
313: * a packet is received or, if a timeout has been defined, the timeout
314: * period expires. If this is a connected socket, the packet host/port are
315: * compared to the connection host/port otherwise the security manager if
316: * present is queried whether the packet host/port is acceptable. Any
317: * packets from unacceptable origins will be silently discarded. The packet
318: * fields are set according to the data received. If the received data is
319: * longer than the packet buffer, it is truncated.
320: *
321: * @param pack
322: * the DatagramPacket to receive data into
323: *
324: * @exception java.io.IOException
325: * If a receive error occurs.
326: */
327: public synchronized void receive(DatagramPacket pack)
328: throws IOException {
329: checkClosedAndBind(true);
330:
331: InetAddress senderAddr;
332: int senderPort;
333: DatagramPacket tempPack = new DatagramPacket(new byte[1], 1);
334:
335: // means that we have received the packet into the temporary buffer
336: boolean copy = false;
337:
338: SecurityManager security = System.getSecurityManager();
339:
340: if (address != null || security != null) {
341: // The socket is connected or we need to check security permissions
342:
343: // Check pack before peeking
344: if (pack == null) {
345: throw new NullPointerException();
346: }
347:
348: // iterate over incoming packets
349: while (true) {
350: copy = false;
351:
352: // let's get sender's address and port
353: try {
354: senderPort = impl.peekData(tempPack);
355: senderAddr = tempPack.getAddress();
356: } catch (SocketException e) {
357: if (e
358: .getMessage()
359: .equals(
360: "The socket does not support the operation")) { //$NON-NLS-1$
361: // receive packet to temporary buffer
362: tempPack = new DatagramPacket(
363: new byte[pack.capacity], pack.capacity);
364: impl.receive(tempPack);
365: // tempPack's length field is now updated, capacity is unchanged
366: // let's extract address & port
367: senderAddr = tempPack.getAddress();
368: senderPort = tempPack.getPort();
369: copy = true;
370: } else {
371: throw e;
372: }
373: }
374:
375: if (address == null) {
376: // if we are not connected let's check if we are allowed to
377: // receive packets from sender's address and port
378: try {
379: security.checkAccept(senderAddr.getHostName(),
380: senderPort);
381: // address & port are valid
382: break;
383: } catch (SecurityException e) {
384: if (!copy) {
385: // drop this packet and continue
386: impl.receive(tempPack);
387: }
388: }
389: } else if (port == senderPort
390: && address.equals(senderAddr)) {
391: // we are connected and the packet came
392: // from the address & port we are connected to
393: break;
394: } else if (!copy) {
395: // drop packet and continue
396: impl.receive(tempPack);
397: }
398: }
399: }
400:
401: if (copy) {
402: System.arraycopy(tempPack.getData(), 0, pack.getData(),
403: pack.getOffset(), tempPack.getLength());
404: // we shouldn't update the pack's capacity field in order to be
405: // compatible with RI
406: pack.length = tempPack.length;
407: pack.setAddress(tempPack.getAddress());
408: pack.setPort(tempPack.getPort());
409: } else {
410: pack.setLength(pack.capacity);
411: impl.receive(pack);
412: // pack's length field is now updated by native code call;
413: // pack's capacity field is unchanged
414: }
415: }
416:
417: /**
418: * Send the packet on this socket. The packet must satisfy the security
419: * policy before it may be sent.
420: *
421: * @param pack
422: * the DatagramPacket to send
423: *
424: * @exception java.io.IOException
425: * If a send error occurs.
426: */
427: public void send(DatagramPacket pack) throws IOException {
428: checkClosedAndBind(true);
429:
430: InetAddress packAddr = pack.getAddress();
431: if (address != null) { // The socket is connected
432: if (packAddr != null) {
433: if (!address.equals(packAddr) || port != pack.getPort()) {
434: throw new IllegalArgumentException(Msg
435: .getString("K0034")); //$NON-NLS-1$
436: }
437: } else {
438: pack.setAddress(address);
439: pack.setPort(port);
440: }
441: } else {
442: // not connected so the target address is not allowed to be null
443: if (packAddr == null) {
444: if (pack.port == -1) {
445: // KA019 Destination address is null
446: throw new NullPointerException(Msg
447: .getString("KA019")); //$NON-NLS-1$
448: }
449: return;
450: }
451: SecurityManager security = System.getSecurityManager();
452: if (security != null) {
453: if (packAddr.isMulticastAddress()) {
454: security.checkMulticast(packAddr);
455: } else {
456: security.checkConnect(packAddr.getHostName(), pack
457: .getPort());
458: }
459: }
460: }
461: impl.send(pack);
462: }
463:
464: /**
465: * Set the socket send buffer size.
466: *
467: * @param size
468: * the buffer size, in bytes. Must be at least one byte.
469: *
470: * @exception java.net.SocketException
471: * If an error occurs while setting the size or the size is
472: * invalid.
473: */
474: public synchronized void setSendBufferSize(int size)
475: throws SocketException {
476: if (size < 1) {
477: throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
478: }
479: checkClosedAndBind(false);
480: impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
481: }
482:
483: /**
484: * Set the socket receive buffer size.
485: *
486: * @param size
487: * the buffer size, in bytes. Must be at least one byte.
488: *
489: * @exception java.net.SocketException
490: * If an error occurs while setting the size or the size is
491: * invalid.
492: */
493: public synchronized void setReceiveBufferSize(int size)
494: throws SocketException {
495: if (size < 1) {
496: throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
497: }
498: checkClosedAndBind(false);
499: impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
500: }
501:
502: /**
503: * Set the SO_RCVTIMEOUT to <code>timeout</code>, in milliseconds. The
504: * receive timeout defines the period a socket will block waiting to receive
505: * data, before throwing an InterruptedIOException.
506: *
507: * @param timeout
508: * the timeout period, in milliseconds
509: *
510: * @exception java.net.SocketException
511: * If an error occurs while setting the timeout or the period
512: * is invalid.
513: */
514: public synchronized void setSoTimeout(int timeout)
515: throws SocketException {
516: if (timeout < 0) {
517: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
518: }
519: checkClosedAndBind(false);
520: impl.setOption(SocketOptions.SO_TIMEOUT, Integer
521: .valueOf(timeout));
522: }
523:
524: /**
525: * Specifies the application's socket implementation factory. This may only
526: * be invoked once over the lifetime of the application.
527: *
528: * @param fac
529: * the socket factory to set
530: * @exception IOException
531: * thrown if the factory has already been set
532: */
533: public static synchronized void setDatagramSocketImplFactory(
534: DatagramSocketImplFactory fac) throws IOException {
535: SecurityManager security = System.getSecurityManager();
536: if (security != null) {
537: security.checkSetFactory();
538: }
539: if (factory != null) {
540: throw new SocketException(Msg.getString("K0044")); //$NON-NLS-1$
541: }
542: factory = fac;
543: }
544:
545: /**
546: * Constructs a DatagramSocket using the specified DatagramSocketImpl. The
547: * DatagramSocket is not bound.
548: *
549: * @param socketImpl
550: * the DatagramSocketImpl to use
551: */
552: protected DatagramSocket(DatagramSocketImpl socketImpl) {
553: if (socketImpl == null) {
554: throw new NullPointerException();
555: }
556: impl = socketImpl;
557: }
558:
559: /**
560: * Constructs a DatagramSocket bound to the host/port specified by the
561: * SocketAddress, or an unbound DatagramSocket if the SocketAddress is null.
562: *
563: * @param localAddr
564: * the local machine address and port to bind to
565: *
566: * @throws IllegalArgumentException
567: * if the SocketAddress is not supported
568: * @throws SocketException
569: * if a problem occurs creating or binding the socket
570: */
571: public DatagramSocket(SocketAddress localAddr)
572: throws SocketException {
573: if (localAddr != null) {
574: if (!(localAddr instanceof InetSocketAddress)) {
575: throw new IllegalArgumentException(Msg.getString(
576: "K0316", localAddr.getClass())); //$NON-NLS-1$
577: }
578: checkListen(((InetSocketAddress) localAddr).getPort());
579: }
580: impl = factory != null ? factory.createDatagramSocketImpl()
581: : SocketImplProvider.getDatagramSocketImpl();
582: impl.create();
583: if (localAddr != null) {
584: try {
585: bind(localAddr);
586: } catch (SocketException e) {
587: close();
588: throw e;
589: }
590: }
591: // SocketOptions.SO_BROADCAST is set by default for DatagramSocket
592: setBroadcast(true);
593: }
594:
595: void checkClosedAndBind(boolean bind) throws SocketException {
596: if (isClosed()) {
597: throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$
598: }
599: if (bind && !isBound()) {
600: checkListen(0);
601: impl.bind(0, InetAddress.ANY);
602: isBound = true;
603: }
604: }
605:
606: /**
607: * Bind the DatagramSocket to the nominated local host/port.
608: *
609: * @param localAddr
610: * the local machine address and port to bind on
611: *
612: * @throws IllegalArgumentException
613: * if the SocketAddress is not supported
614: * @throws SocketException
615: * if the socket is already bound, or a problem occurs during
616: * the bind
617: */
618: public void bind(SocketAddress localAddr) throws SocketException {
619: checkClosedAndBind(false);
620: int localPort = 0;
621: InetAddress addr = InetAddress.ANY;
622: if (localAddr != null) {
623: if (!(localAddr instanceof InetSocketAddress)) {
624: throw new IllegalArgumentException(Msg.getString(
625: "K0316", localAddr.getClass())); //$NON-NLS-1$
626: }
627: InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
628: addr = inetAddr.getAddress();
629: if (addr == null) {
630: throw new SocketException(Msg.getString(
631: "K0317", inetAddr.getHostName())); //$NON-NLS-1$
632: }
633: localPort = inetAddr.getPort();
634: checkListen(localPort);
635: }
636: impl.bind(localPort, addr);
637: isBound = true;
638: }
639:
640: /**
641: * Connect the datagram socket to a remote host and port. The host and port
642: * are validated, thereafter the only validation on send() and receive() is
643: * that the packet address/port matches the connected target.
644: *
645: * @param remoteAddr
646: * the target address and port
647: *
648: * @exception SocketException
649: * if a problem occurs during the connect
650: */
651: public void connect(SocketAddress remoteAddr)
652: throws SocketException {
653: if (remoteAddr == null) {
654: throw new IllegalArgumentException(Msg.getString("K0318")); //$NON-NLS-1$
655: }
656:
657: if (!(remoteAddr instanceof InetSocketAddress)) {
658: throw new IllegalArgumentException(Msg.getString(
659: "K0316", remoteAddr.getClass())); //$NON-NLS-1$
660: }
661:
662: InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
663: if (inetAddr.getAddress() == null) {
664: throw new SocketException(Msg.getString(
665: "K0317", inetAddr.getHostName())); //$NON-NLS-1$
666: }
667:
668: synchronized (lock) {
669: // make sure the socket is open
670: checkClosedAndBind(true);
671:
672: SecurityManager security = System.getSecurityManager();
673: if (security != null) {
674: if (inetAddr.getAddress().isMulticastAddress()) {
675: security.checkMulticast(inetAddr.getAddress());
676: } else {
677: security.checkConnect(inetAddr.getAddress()
678: .getHostName(), inetAddr.getPort());
679: }
680: }
681:
682: // now try to do the connection at the native level. To be
683: // compatible for the case when the address is inaddr_any we just
684: // eat the exception an act as if we are connected at the java level
685: try {
686: impl.connect(inetAddr.getAddress(), inetAddr.getPort());
687: } catch (Exception e) {
688: // not connected at the native level just do what we did before
689: }
690:
691: // if we get here then we connected ok
692: address = inetAddr.getAddress();
693: port = inetAddr.getPort();
694: isConnected = true;
695: }
696: }
697:
698: /**
699: * Return if the socket is bound to a local address and port.
700: *
701: * @return <code>true</code> if the socket is bound to a local address,
702: * <code>false</code> otherwise.
703: */
704: public boolean isBound() {
705: return isBound;
706: }
707:
708: /**
709: * Return if the socket is connected.
710: *
711: * @return <code>true</code> if the socket is connected,
712: * <code>false</code> otherwise.
713: */
714: public boolean isConnected() {
715: return isConnected;
716: }
717:
718: /**
719: * Answer the remote SocketAddress for this socket, or null if the socket is
720: * not connected.
721: *
722: * @return the remote socket address
723: */
724: public SocketAddress getRemoteSocketAddress() {
725: if (!isConnected()) {
726: return null;
727: }
728: return new InetSocketAddress(getInetAddress(), getPort());
729: }
730:
731: /**
732: * Answer the local SocketAddress for this socket, or null if the socket is
733: * not bound.
734: * <p>
735: * This is useful on multihomed hosts.
736: *
737: * @return the local socket address
738: */
739: public SocketAddress getLocalSocketAddress() {
740: if (!isBound()) {
741: return null;
742: }
743: return new InetSocketAddress(getLocalAddress(), getLocalPort());
744: }
745:
746: /**
747: * Set the SO_REUSEADDR socket option.
748: *
749: * @param reuse
750: * the socket SO_REUSEADDR option setting
751: *
752: * @throws SocketException
753: * if the socket is closed or the option is invalid.
754: */
755: public void setReuseAddress(boolean reuse) throws SocketException {
756: checkClosedAndBind(false);
757: impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE
758: : Boolean.FALSE);
759: }
760:
761: /**
762: * Get the state of the SO_REUSEADDR socket option.
763: *
764: * @return <code>true</code> if the SO_REUSEADDR is enabled,
765: * <code>false</code> otherwise.
766: *
767: * @throws SocketException
768: * if the socket is closed or the option is invalid.
769: */
770: public boolean getReuseAddress() throws SocketException {
771: checkClosedAndBind(false);
772: return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
773: .booleanValue();
774: }
775:
776: /**
777: * Set the SO_BROADCAST socket option.
778: *
779: * @param broadcast
780: * the socket SO_BROADCAST option setting
781: *
782: * @throws SocketException
783: * if the socket is closed or the option is invalid.
784: */
785: public void setBroadcast(boolean broadcast) throws SocketException {
786: checkClosedAndBind(false);
787: impl.setOption(SocketOptions.SO_BROADCAST,
788: broadcast ? Boolean.TRUE : Boolean.FALSE);
789: }
790:
791: /**
792: * Get the state of the SO_BROADCAST socket option.
793: *
794: * @return <code>true</code> if the SO_BROADCAST is enabled,
795: * <code>false</code> otherwise.
796: *
797: * @throws SocketException
798: * if the socket is closed or the option is invalid.
799: */
800: public boolean getBroadcast() throws SocketException {
801: checkClosedAndBind(false);
802: return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST))
803: .booleanValue();
804: }
805:
806: /**
807: * Set the IP_TOS socket option.
808: *
809: * @param value
810: * the socket IP_TOS setting
811: *
812: * @throws SocketException
813: * if the socket is closed or the option is invalid.
814: */
815: public void setTrafficClass(int value) throws SocketException {
816: checkClosedAndBind(false);
817: if (value < 0 || value > 255) {
818: throw new IllegalArgumentException();
819: }
820: impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
821: }
822:
823: /**
824: * Get the IP_TOS socket option.
825: *
826: * @return the IP_TOS socket option value
827: *
828: * @throws SocketException
829: * if the option is invalid
830: */
831: public int getTrafficClass() throws SocketException {
832: checkClosedAndBind(false);
833: return ((Number) impl.getOption(SocketOptions.IP_TOS))
834: .intValue();
835: }
836:
837: /**
838: * Return if the socket is closed.
839: *
840: * @return <code>true</code> if the socket is closed, <code>false</code>
841: * otherwise.
842: */
843: public boolean isClosed() {
844: return isClosed;
845: }
846:
847: /**
848: * if DatagramSocket is created by a DatagramChannel, returns the related
849: * DatagramChannel
850: *
851: * @return the related DatagramChannel if any
852: */
853: public DatagramChannel getChannel() {
854: return null;
855: }
856: }
|