DatagramSocket.java revision fdb2704414a9ed92394ada0d1395e4db86889465
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21import java.nio.channels.DatagramChannel; 22 23//import android.net.SocketImplProvider; 24import org.apache.harmony.luni.net.SocketImplProvider; 25import org.apache.harmony.luni.platform.Platform; 26 27import org.apache.harmony.luni.util.Msg; 28 29/** 30 * This class models a socket for sending & receiving datagram packets. 31 * 32 * @see DatagramPacket 33 */ 34public class DatagramSocket { 35 36 DatagramSocketImpl impl; 37 38 InetAddress address; 39 40 int port = -1; 41 42 static DatagramSocketImplFactory factory; 43 44 boolean isBound = false; 45 46 private boolean isConnected = false; 47 48 private boolean isClosed = false; 49 50 private static class Lock { 51 } 52 53 static { 54 Platform.getNetworkSystem().oneTimeInitialization(true); 55 } 56 57 private Object lock = new Lock(); 58 59 /** 60 * Constructs a datagram socket, bound to any available port on the 61 * localhost. 62 * 63 * @throws SocketException 64 * if a problem occurs creating or binding the socket 65 */ 66 public DatagramSocket() throws SocketException { 67 this(0); 68 } 69 70 /** 71 * Returns a datagram socket, bound to the nominated port on the localhost. 72 * 73 * @param aPort 74 * the port to bind on the localhost 75 * 76 * @throws SocketException 77 * if a problem occurs creating or binding the socket 78 */ 79 public DatagramSocket(int aPort) throws SocketException { 80 super(); 81 checkListen(aPort); 82 createSocket(aPort, InetAddress.ANY); 83 } 84 85 /** 86 * Constructs a datagram socket, bound to the nominated localhost/port. 87 * 88 * @param aPort 89 * the port on the localhost to bind 90 * @param addr 91 * the address on the multihomed localhost to bind 92 * 93 * @throws SocketException 94 * if a problem occurs creating or binding the socket 95 */ 96 public DatagramSocket(int aPort, InetAddress addr) throws SocketException { 97 super(); 98 checkListen(aPort); 99 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("K0325", aPort)); //$NON-NLS-1$ 113 } 114 SecurityManager security = System.getSecurityManager(); 115 if (security != null) { 116 security.checkListen(aPort); 117 } 118 } 119 120 /** 121 * Close the socket. 122 */ 123 // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is 124 // noted as not being synchronized. 125 public void close() { 126 isClosed = true; 127 impl.close(); 128 } 129 130 /** 131 * Connect the datagram socket to a remote host and port. The host and port 132 * are validated, thereafter the only validation on send() and receive() is 133 * that the packet address/port matches the connected target. 134 * 135 * @param anAddress 136 * the target address 137 * @param aPort 138 * the target port 139 */ 140 public void connect(InetAddress anAddress, int aPort) { 141 if (anAddress == null || aPort < 0 || aPort > 65535) { 142 throw new IllegalArgumentException(Msg.getString("K0032")); //$NON-NLS-1$ 143 } 144 145 synchronized (lock) { 146 if (isClosed()) { 147 return; 148 } 149 try { 150 checkClosedAndBind(true); 151 } catch (SocketException e) { 152 // Ignored 153 } 154 155 SecurityManager security = System.getSecurityManager(); 156 if (security != null) { 157 if (anAddress.isMulticastAddress()) { 158 security.checkMulticast(anAddress); 159 } else { 160 security.checkConnect(anAddress.getHostName(), aPort); 161 } 162 } 163 164 try { 165 impl.connect(anAddress, aPort); 166 } catch (SocketException e) { 167 // not connected at the native level just do what we did before 168 } 169 address = anAddress; 170 port = aPort; 171 isConnected = true; 172 } 173 } 174 175 /** 176 * 'Disconnect' the datagram socket from a remote host and port. This method 177 * may be called on an unconnected socket. 178 */ 179 public void disconnect() { 180 if (isClosed() || !isConnected()) { 181 return; 182 } 183 impl.disconnect(); 184 address = null; 185 port = -1; 186 isConnected = false; 187 } 188 189 synchronized void createSocket(int aPort, InetAddress addr) 190 throws SocketException { 191 impl = factory != null ? factory.createDatagramSocketImpl() 192 : SocketImplProvider.getDatagramSocketImpl(); 193 impl.create(); 194 try { 195 impl.bind(aPort, addr); 196 isBound = true; 197 } catch (SocketException e) { 198 close(); 199 throw e; 200 } 201 } 202 203 /** 204 * Returns an {@link InetAddress} instance representing the address this 205 * socket has connected to. 206 * 207 * @return if this socket is connected, the address it is connected to. A 208 * <code>null</code> return signifies no connection has been made. 209 */ 210 public InetAddress getInetAddress() { 211 return address; 212 } 213 214 /** 215 * Returns an {@link InetAddress} instance representing the <i>local</i> 216 * address this socket is bound to. 217 * 218 * @return the local address to which the socket is bound 219 */ 220 public InetAddress getLocalAddress() { 221 if (isClosed()) { 222 return null; 223 } 224 if (!isBound()) { 225 return InetAddress.ANY; 226 } 227 InetAddress anAddr = impl.getLocalAddress(); 228 try { 229 SecurityManager security = System.getSecurityManager(); 230 if (security != null) { 231 security.checkConnect(anAddr.getHostName(), -1); 232 } 233 } catch (SecurityException e) { 234 return InetAddress.ANY; 235 } 236 return anAddr; 237 } 238 239 /** 240 * Answer the local port to which the socket is bound. 241 * 242 * @return int local port to which the socket is bound 243 */ 244 public int getLocalPort() { 245 if (isClosed()) { 246 return -1; 247 } 248 if (!isBound()) { 249 return 0; 250 } 251 return impl.getLocalPort(); 252 } 253 254 /** 255 * Returns the number of the remote port this socket is connected to. 256 * 257 * @return int the remote port number that this socket has connected to. A 258 * return of <code>-1</code> indicates that there is no connection 259 * in place. 260 */ 261 public int getPort() { 262 return port; 263 } 264 265 /** 266 * Returns whether this socket is multicast. 267 * 268 * @return Always returns false. 269 */ 270 boolean isMulticastSocket() { 271 return false; 272 } 273 274 /** 275 * Answer the socket receive buffer size (SO_RCVBUF). 276 * 277 * @return int socket receive buffer size 278 * 279 * @exception SocketException 280 * when an error occurs 281 */ 282 public synchronized int getReceiveBufferSize() throws SocketException { 283 checkClosedAndBind(false); 284 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 285 } 286 287 /** 288 * Answer the socket send buffer size (SO_SNDBUF). 289 * 290 * @return int socket send buffer size 291 * 292 * @exception SocketException 293 * when an error occurs 294 */ 295 public synchronized int getSendBufferSize() throws SocketException { 296 checkClosedAndBind(false); 297 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); 298 } 299 300 /** 301 * Answer the socket receive timeout (SO_RCVTIMEOUT), in milliseconds. Zero 302 * implies the timeout is disabled. 303 * 304 * @return int socket receive timeout 305 * 306 * @exception SocketException 307 * when an error occurs 308 */ 309 public synchronized int getSoTimeout() throws SocketException { 310 checkClosedAndBind(false); 311 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 312 } 313 314 /** 315 * Receive on this socket into the packet argument. This method blocks until 316 * a packet is received or, if a timeout has been defined, the timeout 317 * period expires. If this is a connected socket, the packet host/port are 318 * compared to the connection host/port otherwise the security manager if 319 * present is queried whether the packet host/port is acceptable. Any 320 * packets from unacceptable origins will be silently discarded. The packet 321 * fields are set according to the data received. If the received data is 322 * longer than the packet buffer, it is truncated. 323 * 324 * @param pack 325 * the DatagramPacket to receive data into 326 * 327 * @exception java.io.IOException 328 * If a receive error occurs. 329 */ 330 public synchronized void receive(DatagramPacket pack) throws IOException { 331 checkClosedAndBind(true); 332 333 boolean secure = true; 334 335 InetAddress senderAddr = null; 336 337 int senderPort = 0; 338 DatagramPacket tempPack = new DatagramPacket(new byte[1], 1); 339 boolean copy = false; 340 341 SecurityManager security = System.getSecurityManager(); 342 if (address != null || security != null) { // The socket is connected 343 // Check pack before peeking 344 if (pack == null) { 345 throw new NullPointerException(); 346 } 347 secure = false; 348 while (!secure) { 349 copy = false; 350 try { 351 senderPort = impl.peekData(tempPack); 352 senderAddr = tempPack.getAddress(); 353 } catch (SocketException e) { 354 if (e.getMessage().equals( 355 "The socket does not support the operation")) { //$NON-NLS-1$ 356 tempPack = new DatagramPacket(new byte[pack.length], 357 pack.getLength()); 358 impl.receive(tempPack); 359 senderAddr = tempPack.getAddress(); 360 senderPort = tempPack.getPort(); 361 copy = true; 362 } else { 363 throw e; 364 } 365 } 366 if (address == null) { 367 try { 368 security.checkAccept(senderAddr.getHostName(), 369 senderPort); 370 if (!copy) { 371 secure = true; 372 } 373 break; 374 } catch (SecurityException e) { 375 if (!copy) { 376 if (tempPack == null) { 377 tempPack = new DatagramPacket( 378 new byte[pack.length], pack.length); 379 } 380 impl.receive(tempPack); 381 } 382 } 383 } else if (port == senderPort && address.equals(senderAddr)) { 384 if (!copy) { 385 secure = true; 386 } 387 break; 388 } else if (!copy) { 389 if (tempPack == null) { 390 tempPack = new DatagramPacket(new byte[pack.length], 391 pack.length); 392 } 393 impl.receive(tempPack); 394 } 395 } 396 } 397 if (copy) { 398 System.arraycopy(tempPack.getData(), 0, pack.getData(), pack 399 .getOffset(), tempPack.getLength()); 400 pack.setLength(tempPack.getLength()); 401 pack.setAddress(tempPack.getAddress()); 402 pack.setPort(tempPack.getPort()); 403 } 404 if (secure) { 405 impl.receive(pack); 406 } 407 } 408 409 /** 410 * Send the packet on this socket. The packet must satisfy the security 411 * policy before it may be sent. 412 * 413 * @param pack 414 * the DatagramPacket to send 415 * 416 * @exception java.io.IOException 417 * If a send error occurs. 418 */ 419 public void send(DatagramPacket pack) throws IOException { 420 checkClosedAndBind(true); 421 422 InetAddress packAddr = pack.getAddress(); 423 if (address != null) { // The socket is connected 424 if (packAddr != null) { 425 if (!address.equals(packAddr) || port != pack.getPort()) { 426 throw new IllegalArgumentException(Msg.getString("K0034")); //$NON-NLS-1$ 427 } 428 } else { 429 pack.setAddress(address); 430 pack.setPort(port); 431 } 432 } else { 433 // not connected so the target address is not allowed to be null 434 if (packAddr == null) { 435 if (pack.port == -1) { 436 // KA019 Destination address is null 437 throw new NullPointerException(Msg.getString("KA019")); //$NON-NLS-1$ 438 } 439 return; 440 } 441 SecurityManager security = System.getSecurityManager(); 442 if (security != null) { 443 if (packAddr.isMulticastAddress()) { 444 security.checkMulticast(packAddr); 445 } else { 446 security.checkConnect(packAddr.getHostName(), pack 447 .getPort()); 448 } 449 } 450 } 451 impl.send(pack); 452 } 453 454 /** 455 * Set the socket send buffer size. 456 * 457 * @param size 458 * the buffer size, in bytes. Must be at least one byte. 459 * 460 * @exception java.net.SocketException 461 * If an error occurs while setting the size or the size is 462 * invalid. 463 */ 464 public synchronized void setSendBufferSize(int size) throws SocketException { 465 if (size < 1) { 466 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ 467 } 468 checkClosedAndBind(false); 469 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size)); 470 } 471 472 /** 473 * Set the socket receive buffer size. 474 * 475 * @param size 476 * the buffer size, in bytes. Must be at least one byte. 477 * 478 * @exception java.net.SocketException 479 * If an error occurs while setting the size or the size is 480 * invalid. 481 */ 482 public synchronized void setReceiveBufferSize(int size) 483 throws SocketException { 484 if (size < 1) { 485 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ 486 } 487 checkClosedAndBind(false); 488 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 489 } 490 491 /** 492 * Set the SO_RCVTIMEOUT to <code>timeout</code>, in milliseconds. The 493 * receive timeout defines the period a socket will block waiting to receive 494 * data, before throwing an InterruptedIOException. 495 * 496 * @param timeout 497 * the timeout period, in milliseconds 498 * 499 * @exception java.net.SocketException 500 * If an error occurs while setting the timeout or the period 501 * is invalid. 502 */ 503 public synchronized void setSoTimeout(int timeout) throws SocketException { 504 if (timeout < 0) { 505 throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ 506 } 507 checkClosedAndBind(false); 508 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 509 } 510 511 /** 512 * Specifies the application's socket implementation factory. This may only 513 * be invoked once over the lifetime of the application. 514 * 515 * @param fac 516 * the socket factory to set 517 * @exception IOException 518 * thrown if the factory has already been set 519 */ 520 public static synchronized void setDatagramSocketImplFactory( 521 DatagramSocketImplFactory fac) throws IOException { 522 SecurityManager security = System.getSecurityManager(); 523 if (security != null) { 524 security.checkSetFactory(); 525 } 526 if (factory != null) { 527 throw new SocketException(Msg.getString("K0044")); //$NON-NLS-1$ 528 } 529 factory = fac; 530 } 531 532 /** 533 * Constructs a DatagramSocket using the specified DatagramSocketImpl. The 534 * DatagramSocket is not bound. 535 * 536 * @param socketImpl 537 * the DatagramSocketImpl to use 538 */ 539 protected DatagramSocket(DatagramSocketImpl socketImpl) { 540 if (socketImpl == null) { 541 throw new NullPointerException(); 542 } 543 impl = socketImpl; 544 } 545 546 /** 547 * Constructs a DatagramSocket bound to the host/port specified by the 548 * SocketAddress, or an unbound DatagramSocket if the SocketAddress is null. 549 * 550 * @param localAddr 551 * the local machine address and port to bind to 552 * 553 * @throws IllegalArgumentException 554 * if the SocketAddress is not supported 555 * @throws SocketException 556 * if a problem occurs creating or binding the socket 557 */ 558 public DatagramSocket(SocketAddress localAddr) throws SocketException { 559 if (localAddr != null) { 560 if (!(localAddr instanceof InetSocketAddress)) { 561 throw new IllegalArgumentException(Msg.getString( 562 "K0316", localAddr.getClass())); //$NON-NLS-1$ 563 } 564 checkListen(((InetSocketAddress) localAddr).getPort()); 565 } 566 impl = factory != null ? factory.createDatagramSocketImpl() 567 : SocketImplProvider.getDatagramSocketImpl(); 568 impl.create(); 569 if (localAddr != null) { 570 try { 571 bind(localAddr); 572 } catch (SocketException e) { 573 close(); 574 throw e; 575 } 576 } 577 // SocketOptions.SO_BROADCAST is set by default for DatagramSocket 578 setBroadcast(true); 579 } 580 581 void checkClosedAndBind(boolean bind) throws SocketException { 582 if (isClosed()) { 583 throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$ 584 } 585 if (bind && !isBound()) { 586 checkListen(0); 587 impl.bind(0, InetAddress.ANY); 588 isBound = true; 589 } 590 } 591 592 /** 593 * Bind the DatagramSocket to the nominated local host/port. 594 * 595 * @param localAddr 596 * the local machine address and port to bind on 597 * 598 * @throws IllegalArgumentException 599 * if the SocketAddress is not supported 600 * @throws SocketException 601 * if the socket is already bound, or a problem occurs during 602 * the bind 603 */ 604 public void bind(SocketAddress localAddr) throws SocketException { 605 checkClosedAndBind(false); 606 int localPort = 0; 607 InetAddress addr = InetAddress.ANY; 608 if (localAddr != null) { 609 if (!(localAddr instanceof InetSocketAddress)) { 610 throw new IllegalArgumentException(Msg.getString( 611 "K0316", localAddr.getClass())); //$NON-NLS-1$ 612 } 613 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 614 addr = inetAddr.getAddress(); 615 if (addr == null) { 616 throw new SocketException(Msg.getString( 617 "K0317", inetAddr.getHostName())); //$NON-NLS-1$ 618 } 619 localPort = inetAddr.getPort(); 620 checkListen(localPort); 621 } 622 impl.bind(localPort, addr); 623 isBound = true; 624 } 625 626 /** 627 * Connect the datagram socket to a remote host and port. The host and port 628 * are validated, thereafter the only validation on send() and receive() is 629 * that the packet address/port matches the connected target. 630 * 631 * @param remoteAddr 632 * the target address and port 633 * 634 * @exception SocketException 635 * if a problem occurs during the connect 636 */ 637 public void connect(SocketAddress remoteAddr) throws SocketException { 638 if (remoteAddr == null) { 639 throw new IllegalArgumentException(Msg.getString("K0318")); //$NON-NLS-1$ 640 } 641 642 if (!(remoteAddr instanceof InetSocketAddress)) { 643 throw new IllegalArgumentException(Msg.getString( 644 "K0316", remoteAddr.getClass())); //$NON-NLS-1$ 645 } 646 647 InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr; 648 if (inetAddr.getAddress() == null) { 649 throw new SocketException(Msg.getString( 650 "K0317", inetAddr.getHostName())); //$NON-NLS-1$ 651 } 652 653 synchronized (lock) { 654 // make sure the socket is open 655 checkClosedAndBind(true); 656 657 SecurityManager security = System.getSecurityManager(); 658 if (security != null) { 659 if (inetAddr.getAddress().isMulticastAddress()) { 660 security.checkMulticast(inetAddr.getAddress()); 661 } else { 662 security.checkConnect(inetAddr.getAddress().getHostName(), 663 inetAddr.getPort()); 664 } 665 } 666 667 // now try to do the connection at the native level. To be 668 // compatible for the case when the address is inaddr_any we just 669 // eat the exception an act as if we are connected at the java level 670 try { 671 impl.connect(inetAddr.getAddress(), inetAddr.getPort()); 672 } catch (Exception e) { 673 // not connected at the native level just do what we did before 674 } 675 676 // if we get here then we connected ok 677 address = inetAddr.getAddress(); 678 port = inetAddr.getPort(); 679 isConnected = true; 680 } 681 } 682 683 /** 684 * Return if the socket is bound to a local address and port. 685 * 686 * @return <code>true</code> if the socket is bound to a local address, 687 * <code>false</code> otherwise. 688 */ 689 public boolean isBound() { 690 return isBound; 691 } 692 693 /** 694 * Return if the socket is connected. 695 * 696 * @return <code>true</code> if the socket is connected, 697 * <code>false</code> otherwise. 698 */ 699 public boolean isConnected() { 700 return isConnected; 701 } 702 703 /** 704 * Answer the remote SocketAddress for this socket, or null if the socket is 705 * not connected. 706 * 707 * @return the remote socket address 708 */ 709 public SocketAddress getRemoteSocketAddress() { 710 if (!isConnected()) { 711 return null; 712 } 713 return new InetSocketAddress(getInetAddress(), getPort()); 714 } 715 716 /** 717 * Answer the local SocketAddress for this socket, or null if the socket is 718 * not bound. 719 * <p> 720 * This is useful on multihomed hosts. 721 * 722 * @return the local socket address 723 */ 724 public SocketAddress getLocalSocketAddress() { 725 if (!isBound()) { 726 return null; 727 } 728 return new InetSocketAddress(getLocalAddress(), getLocalPort()); 729 } 730 731 /** 732 * Set the SO_REUSEADDR socket option. 733 * 734 * @param reuse 735 * the socket SO_REUSEADDR option setting 736 * 737 * @throws SocketException 738 * if the socket is closed or the option is invalid. 739 */ 740 public void setReuseAddress(boolean reuse) throws SocketException { 741 checkClosedAndBind(false); 742 impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE 743 : Boolean.FALSE); 744 } 745 746 /** 747 * Get the state of the SO_REUSEADDR socket option. 748 * 749 * @return <code>true</code> if the SO_REUSEADDR is enabled, 750 * <code>false</code> otherwise. 751 * 752 * @throws SocketException 753 * if the socket is closed or the option is invalid. 754 */ 755 public boolean getReuseAddress() throws SocketException { 756 checkClosedAndBind(false); 757 return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)) 758 .booleanValue(); 759 } 760 761 /** 762 * Set the SO_BROADCAST socket option. 763 * 764 * @param broadcast 765 * the socket SO_BROADCAST option setting 766 * 767 * @throws SocketException 768 * if the socket is closed or the option is invalid. 769 */ 770 public void setBroadcast(boolean broadcast) throws SocketException { 771 checkClosedAndBind(false); 772 impl.setOption(SocketOptions.SO_BROADCAST, broadcast ? Boolean.TRUE 773 : Boolean.FALSE); 774 } 775 776 /** 777 * Get the state of the SO_BROADCAST socket option. 778 * 779 * @return <code>true</code> if the SO_BROADCAST is enabled, 780 * <code>false</code> otherwise. 781 * 782 * @throws SocketException 783 * if the socket is closed or the option is invalid. 784 */ 785 public boolean getBroadcast() throws SocketException { 786 checkClosedAndBind(false); 787 return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST)) 788 .booleanValue(); 789 } 790 791 /** 792 * Set the IP_TOS socket option. 793 * 794 * @param value 795 * the socket IP_TOS setting 796 * 797 * @throws SocketException 798 * if the socket is closed or the option is invalid. 799 */ 800 public void setTrafficClass(int value) throws SocketException { 801 checkClosedAndBind(false); 802 if (value < 0 || value > 255) { 803 throw new IllegalArgumentException(); 804 } 805 impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value)); 806 } 807 808 /** 809 * Get the IP_TOS socket option. 810 * 811 * @return the IP_TOS socket option value 812 * 813 * @throws SocketException 814 * if the option is invalid 815 */ 816 public int getTrafficClass() throws SocketException { 817 checkClosedAndBind(false); 818 return ((Number) impl.getOption(SocketOptions.IP_TOS)).intValue(); 819 } 820 821 /** 822 * Return if the socket is closed. 823 * 824 * @return <code>true</code> if the socket is closed, <code>false</code> 825 * otherwise. 826 */ 827 public boolean isClosed() { 828 return isClosed; 829 } 830 831 /** 832 * if DatagramSocket is created by a DatagramChannel, returns the related 833 * DatagramChannel 834 * 835 * @return the related DatagramChannel if any 836 */ 837 public DatagramChannel getChannel() { 838 return null; 839 } 840} 841