DatagramSocket.java revision 2cd82d7111f68ff63145ef7c393bf1479ff06223
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 23import org.apache.harmony.luni.net.PlainDatagramSocketImpl; 24import org.apache.harmony.luni.platform.Platform; 25 26/** 27 * This class implements a UDP socket for sending and receiving {@code 28 * DatagramPacket}. A {@code DatagramSocket} object can be used for both 29 * endpoints of a connection for a packet delivery service. 30 * 31 * @see DatagramPacket 32 * @see DatagramSocketImplFactory 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 private Object lock = new Lock(); 54 55 /** 56 * Constructs a UDP datagram socket which is bound to any available port on 57 * the localhost. 58 * 59 * @throws SocketException 60 * if an error occurs while creating or binding the socket. 61 */ 62 public DatagramSocket() throws SocketException { 63 this(0); 64 } 65 66 /** 67 * Constructs a UDP datagram socket which is bound to the specific port 68 * {@code aPort} on the localhost. Valid values for {@code aPort} are 69 * between 0 and 65535 inclusive. 70 * 71 * @param aPort 72 * the port to bind on the localhost. 73 * @throws SocketException 74 * if an error occurs while creating or binding the socket. 75 */ 76 public DatagramSocket(int aPort) throws SocketException { 77 super(); 78 checkListen(aPort); 79 createSocket(aPort, Inet4Address.ANY); 80 } 81 82 /** 83 * Constructs a UDP datagram socket which is bound to the specific local 84 * address {@code addr} on port {@code aPort}. Valid values for {@code 85 * aPort} are between 0 and 65535 inclusive. 86 * 87 * @param aPort 88 * the port to bind on the localhost. 89 * @param addr 90 * the address to bind on the localhost. 91 * @throws SocketException 92 * if an error occurs while creating or binding the socket. 93 */ 94 public DatagramSocket(int aPort, InetAddress addr) throws SocketException { 95 super(); 96 checkListen(aPort); 97 createSocket(aPort, null == addr ? Inet4Address.ANY : addr); 98 } 99 100 /** 101 * Sends prior to attempting to bind the socket, checks whether the port is 102 * within the valid port range and verifies with the security manager that 103 * the port may be bound by the current context. 104 * 105 * @param aPort 106 * the port on the localhost that is to be bound. 107 */ 108 void checkListen(int aPort) { 109 if (aPort < 0 || aPort > 65535) { 110 throw new IllegalArgumentException("Port out of range: " + aPort); 111 } 112 SecurityManager security = System.getSecurityManager(); 113 if (security != null) { 114 security.checkListen(aPort); 115 } 116 } 117 118 /** 119 * Closes this UDP datagram socket and all possibly associated channels. 120 */ 121 // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is 122 // noted as not being synchronized. 123 public void close() { 124 isClosed = true; 125 impl.close(); 126 } 127 128 /** 129 * Connects this UDP datagram socket to the specific target host with the 130 * address {@code anAdress} on port {@code aPort}. The host and port are 131 * validated, thereafter the only validation on {@code send()} and {@code 132 * receive()} is to check whether the packet address/port matches the 133 * connected target. 134 * 135 * @param anAddress 136 * the target address of this socket. 137 * @param aPort 138 * the target port of this socket. 139 */ 140 public void connect(InetAddress anAddress, int aPort) { 141 if (anAddress == null || aPort < 0 || aPort > 65535) { 142 throw new IllegalArgumentException("Address null or destination port out of range"); 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 * Disconnects this UDP datagram socket from the remote host. This method 177 * called on an unconnected socket does nothing. 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 : new PlainDatagramSocketImpl(); 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 * Gets the {@code InetAddress} instance representing the remote address to 205 * which this UDP datagram socket is connected. 206 * 207 * @return the remote address this socket is connected to or {@code null} if 208 * this socket is not connected. 209 */ 210 public InetAddress getInetAddress() { 211 return address; 212 } 213 214 /** 215 * Gets the {@code InetAddress} instance representing the bound local 216 * address of this UDP datagram socket. 217 * 218 * @return the local address to which this socket is bound to or {@code 219 * null} if this socket is closed. 220 */ 221 public InetAddress getLocalAddress() { 222 if (isClosed()) { 223 return null; 224 } 225 if (!isBound()) { 226 return Inet4Address.ANY; 227 } 228 InetAddress anAddr = impl.getLocalAddress(); 229 try { 230 SecurityManager security = System.getSecurityManager(); 231 if (security != null) { 232 security.checkConnect(anAddr.getHostName(), -1); 233 } 234 } catch (SecurityException e) { 235 return Inet4Address.ANY; 236 } 237 return anAddr; 238 } 239 240 /** 241 * Gets the local port which this socket is bound to. 242 * 243 * @return the local port of this socket or {@code -1} if this socket is 244 * closed and {@code 0} if it is unbound. 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 * Gets the remote port which this socket is connected to. 258 * 259 * @return the remote port of this socket. The return value {@code -1} 260 * indicates that this socket is not connected. 261 */ 262 public int getPort() { 263 return port; 264 } 265 266 /** 267 * Indicates whether this socket is multicast or not. 268 * 269 * @return the return value is always {@code false}. 270 */ 271 boolean isMulticastSocket() { 272 return false; 273 } 274 275 /** 276 * Gets the socket receive buffer size. ( {@code SocketOptions.SO_RCVBUF} ) 277 * 278 * @return the input buffer size. 279 * @throws SocketException 280 * if an error occurs while getting the option value. 281 */ 282 public synchronized int getReceiveBufferSize() throws SocketException { 283 checkClosedAndBind(false); 284 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 285 } 286 287 /** 288 * Gets the socket send buffer size. ( {@code SocketOptions.SO_SNDBUF} ) 289 * 290 * @return the output buffer size. 291 * @throws SocketException 292 * if an error occurs while getting the option value. 293 */ 294 public synchronized int getSendBufferSize() throws SocketException { 295 checkClosedAndBind(false); 296 return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); 297 } 298 299 /** 300 * Gets the socket {@link SocketOptions#SO_TIMEOUT receive timeout}. 301 * 302 * @throws SocketException 303 * if an error occurs while getting the option value. 304 */ 305 public synchronized int getSoTimeout() throws SocketException { 306 checkClosedAndBind(false); 307 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 308 } 309 310 /** 311 * Receives a packet from this socket and stores it in the argument {@code 312 * pack}. All fields of {@code pack} must be set according to the data 313 * received. If the received data is longer than the packet buffer size it 314 * is truncated. This method blocks until a packet is received or a timeout 315 * has expired. If a security manager exists, its {@code checkAccept} method 316 * determines whether or not a packet is discarded. Any packets from 317 * unacceptable origins are silently discarded. 318 * 319 * @param pack 320 * the {@code DatagramPacket} to store the received data. 321 * @throws IOException 322 * if an error occurs while receiving the packet. 323 */ 324 public synchronized void receive(DatagramPacket pack) throws IOException { 325 checkClosedAndBind(true); 326 327 InetAddress senderAddr; 328 int senderPort; 329 DatagramPacket tempPack = new DatagramPacket(new byte[1], 1); 330 331 // means that we have received the packet into the temporary buffer 332 boolean copy = false; 333 334 SecurityManager security = System.getSecurityManager(); 335 336 if (address != null || security != null) { 337 // The socket is connected or we need to check security permissions 338 339 // Check pack before peeking 340 if (pack == null) { 341 throw new NullPointerException(); 342 } 343 344 // iterate over incoming packets 345 while (true) { 346 copy = false; 347 348 // let's get sender's address and port 349 try { 350 senderPort = impl.peekData(tempPack); 351 senderAddr = tempPack.getAddress(); 352 } catch (SocketException e) { 353 if (e.getMessage().equals( 354 "The socket does not support the operation")) { 355 // receive packet to temporary buffer 356 tempPack = new DatagramPacket(new byte[pack.getCapacity()], 357 pack.getCapacity()); 358 impl.receive(tempPack); 359 // tempPack's length field is now updated, capacity is unchanged 360 // let's extract address & port 361 senderAddr = tempPack.getAddress(); 362 senderPort = tempPack.getPort(); 363 copy = true; 364 } else { 365 throw e; 366 } 367 } 368 369 if (address == null) { 370 // if we are not connected let's check if we are allowed to 371 // receive packets from sender's address and port 372 try { 373 security.checkAccept(senderAddr.getHostName(), 374 senderPort); 375 // address & port are valid 376 break; 377 } catch (SecurityException e) { 378 if (!copy) { 379 // drop this packet and continue 380 impl.receive(tempPack); 381 } 382 } 383 } else if (port == senderPort && address.equals(senderAddr)) { 384 // we are connected and the packet came 385 // from the address & port we are connected to 386 break; 387 } else if (!copy) { 388 // drop packet and continue 389 impl.receive(tempPack); 390 } 391 } 392 } 393 394 if (copy) { 395 System.arraycopy(tempPack.getData(), 0, pack.getData(), pack 396 .getOffset(), tempPack.getLength()); 397 // we shouldn't update the pack's capacity field in order to be 398 // compatible with RI 399 pack.setLengthOnly(tempPack.getLength()); 400 pack.setAddress(tempPack.getAddress()); 401 pack.setPort(tempPack.getPort()); 402 } else { 403 pack.setLength(pack.getCapacity()); 404 impl.receive(pack); 405 // pack's length field is now updated by native code call; 406 // pack's capacity field is unchanged 407 } 408 } 409 410 /** 411 * Sends a packet over this socket. The packet must satisfy the security 412 * policy before it may be sent. If a security manager is installed, this 413 * method checks whether it is allowed to send this packet to the specified 414 * address. 415 * 416 * @param pack 417 * the {@code DatagramPacket} which has to be sent. 418 * @throws IOException 419 * if an error occurs while sending the packet. 420 */ 421 public void send(DatagramPacket pack) throws IOException { 422 checkClosedAndBind(true); 423 424 InetAddress packAddr = pack.getAddress(); 425 if (address != null) { // The socket is connected 426 if (packAddr != null) { 427 if (!address.equals(packAddr) || port != pack.getPort()) { 428 throw new IllegalArgumentException("Packet address mismatch with connected address"); 429 } 430 } else { 431 pack.setAddress(address); 432 pack.setPort(port); 433 } 434 } else { 435 // not connected so the target address is not allowed to be null 436 if (packAddr == null) { 437 if (pack.getPort() == -1) { 438 throw new NullPointerException("Destination address is null"); 439 } 440 return; 441 } 442 SecurityManager security = System.getSecurityManager(); 443 if (security != null) { 444 if (packAddr.isMulticastAddress()) { 445 security.checkMulticast(packAddr); 446 } else { 447 security.checkConnect(packAddr.getHostName(), pack 448 .getPort()); 449 } 450 } 451 } 452 impl.send(pack); 453 } 454 455 /** 456 * Sets the socket send buffer size. This buffer size determines which the 457 * maximum packet size is that can be sent over this socket. It depends on 458 * the network implementation what will happen if the packet is bigger than 459 * the buffer size. ( {@code SocketOptions.SO_SNDBUF} ) 460 * 461 * @param size 462 * the buffer size in bytes. The size must be at least one byte. 463 * @throws SocketException 464 * if an error occurs while setting the option. 465 */ 466 public synchronized void setSendBufferSize(int size) throws SocketException { 467 if (size < 1) { 468 throw new IllegalArgumentException("size < 1"); 469 } 470 checkClosedAndBind(false); 471 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size)); 472 } 473 474 /** 475 * Sets the socket receive buffer size. This buffer size determines which 476 * the maximum packet size is that can be received over this socket. It 477 * depends on the network implementation what will happen if the packet is 478 * bigger than the buffer size. ( {@code SocketOptions.SO_RCVBUF} ) 479 * 480 * @param size 481 * the buffer size in bytes. The size must be at least one byte. 482 * @throws SocketException 483 * if an error occurs while setting the option. 484 */ 485 public synchronized void setReceiveBufferSize(int size) throws SocketException { 486 if (size < 1) { 487 throw new IllegalArgumentException("size < 1"); 488 } 489 checkClosedAndBind(false); 490 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 491 } 492 493 /** 494 * Sets the {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds for this socket. 495 * This receive timeout defines the period the socket will block waiting to 496 * receive data before throwing an {@code InterruptedIOException}. The value 497 * {@code 0} (default) is used to set an infinite timeout. To have effect 498 * this option must be set before the blocking method was called. 499 * 500 * @param timeout the timeout in milliseconds or 0 for no timeout. 501 * @throws SocketException 502 * if an error occurs while setting the option. 503 */ 504 public synchronized void setSoTimeout(int timeout) throws SocketException { 505 if (timeout < 0) { 506 throw new IllegalArgumentException("timeout < 0"); 507 } 508 checkClosedAndBind(false); 509 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 510 } 511 512 /** 513 * Sets the socket implementation factory. This may only be invoked once 514 * over the lifetime of the application. This factory is used to create 515 * a new datagram socket implementation. If a security manager is set its 516 * method {@code checkSetFactory()} is called to check if the operation is 517 * allowed. A {@code SecurityException} is thrown if the operation is not 518 * allowed. 519 * 520 * @param fac 521 * the socket factory to use. 522 * @throws IOException 523 * if the factory has already been set. 524 * @see DatagramSocketImplFactory 525 */ 526 public static synchronized void setDatagramSocketImplFactory( 527 DatagramSocketImplFactory fac) throws IOException { 528 SecurityManager security = System.getSecurityManager(); 529 if (security != null) { 530 security.checkSetFactory(); 531 } 532 if (factory != null) { 533 throw new SocketException("Factory already set"); 534 } 535 factory = fac; 536 } 537 538 /** 539 * Constructs a new {@code DatagramSocket} using the specific datagram 540 * socket implementation {@code socketImpl}. The created {@code 541 * DatagramSocket} will not be bound. 542 * 543 * @param socketImpl 544 * the DatagramSocketImpl to use. 545 */ 546 protected DatagramSocket(DatagramSocketImpl socketImpl) { 547 if (socketImpl == null) { 548 throw new NullPointerException(); 549 } 550 impl = socketImpl; 551 } 552 553 /** 554 * Constructs a new {@code DatagramSocket} bound to the host/port specified 555 * by the {@code SocketAddress} {@code localAddr} or an unbound {@code 556 * DatagramSocket} if the {@code SocketAddress} is {@code null}. 557 * 558 * @param localAddr 559 * the local machine address and port to bind to. 560 * @throws IllegalArgumentException 561 * if the SocketAddress is not supported 562 * @throws SocketException 563 * if a problem occurs creating or binding the socket. 564 */ 565 public DatagramSocket(SocketAddress localAddr) throws SocketException { 566 if (localAddr != null) { 567 if (!(localAddr instanceof InetSocketAddress)) { 568 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 569 localAddr.getClass()); 570 } 571 checkListen(((InetSocketAddress) localAddr).getPort()); 572 } 573 impl = factory != null ? factory.createDatagramSocketImpl() 574 : new PlainDatagramSocketImpl(); 575 impl.create(); 576 if (localAddr != null) { 577 try { 578 bind(localAddr); 579 } catch (SocketException e) { 580 close(); 581 throw e; 582 } 583 } 584 // SocketOptions.SO_BROADCAST is set by default for DatagramSocket 585 setBroadcast(true); 586 } 587 588 void checkClosedAndBind(boolean bind) throws SocketException { 589 if (isClosed()) { 590 throw new SocketException("Socket is closed"); 591 } 592 if (bind && !isBound()) { 593 checkListen(0); 594 impl.bind(0, Inet4Address.ANY); 595 isBound = true; 596 } 597 } 598 599 /** 600 * Binds this socket to the local address and port specified by {@code 601 * localAddr}. If this value is {@code null} any free port on a valid local 602 * address is used. 603 * 604 * @param localAddr 605 * the local machine address and port to bind on. 606 * @throws IllegalArgumentException 607 * if the SocketAddress is not supported 608 * @throws SocketException 609 * if the socket is already bound or a problem occurs during 610 * binding. 611 */ 612 public void bind(SocketAddress localAddr) throws SocketException { 613 checkClosedAndBind(false); 614 int localPort = 0; 615 InetAddress addr = Inet4Address.ANY; 616 if (localAddr != null) { 617 if (!(localAddr instanceof InetSocketAddress)) { 618 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 619 localAddr.getClass()); 620 } 621 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 622 addr = inetAddr.getAddress(); 623 if (addr == null) { 624 throw new SocketException("Host is unresolved: " + inetAddr.getHostName()); 625 } 626 localPort = inetAddr.getPort(); 627 checkListen(localPort); 628 } 629 impl.bind(localPort, addr); 630 isBound = true; 631 } 632 633 /** 634 * Connects this datagram socket to the remote host and port specified by 635 * {@code remoteAddr}. The host and port are validated, thereafter the only 636 * validation on {@code send()} and {@code receive()} is that the packet 637 * address/port matches the connected target. 638 * 639 * @param remoteAddr 640 * the address and port of the target host. 641 * @throws SocketException 642 * if an error occurs during connecting. 643 */ 644 public void connect(SocketAddress remoteAddr) throws SocketException { 645 if (remoteAddr == null) { 646 throw new IllegalArgumentException("remoteAddr == null"); 647 } 648 649 if (!(remoteAddr instanceof InetSocketAddress)) { 650 throw new IllegalArgumentException("Remote address not an InetSocketAddress: " + 651 remoteAddr.getClass()); 652 } 653 654 InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr; 655 if (inetAddr.getAddress() == null) { 656 throw new SocketException("Host is unresolved: " + inetAddr.getHostName()); 657 } 658 659 synchronized (lock) { 660 // make sure the socket is open 661 checkClosedAndBind(true); 662 663 SecurityManager security = System.getSecurityManager(); 664 if (security != null) { 665 if (inetAddr.getAddress().isMulticastAddress()) { 666 security.checkMulticast(inetAddr.getAddress()); 667 } else { 668 security.checkConnect(inetAddr.getAddress().getHostName(), 669 inetAddr.getPort()); 670 } 671 } 672 673 // now try to do the connection at the native level. To be 674 // compatible for the case when the address is inaddr_any we just 675 // eat the exception an act as if we are connected at the java level 676 try { 677 impl.connect(inetAddr.getAddress(), inetAddr.getPort()); 678 } catch (Exception e) { 679 // not connected at the native level just do what we did before 680 } 681 682 // if we get here then we connected ok 683 address = inetAddr.getAddress(); 684 port = inetAddr.getPort(); 685 isConnected = true; 686 } 687 } 688 689 /** 690 * Determines whether the socket is bound to an address or not. 691 * 692 * @return {@code true} if the socket is bound, {@code false} otherwise. 693 */ 694 public boolean isBound() { 695 return isBound; 696 } 697 698 /** 699 * Determines whether the socket is connected to a target host. 700 * 701 * @return {@code true} if the socket is connected, {@code false} otherwise. 702 */ 703 public boolean isConnected() { 704 return isConnected; 705 } 706 707 /** 708 * Gets the address and port of the connected remote host. If this socket is 709 * not connected yet, {@code null} is returned. 710 * 711 * @return the remote socket address. 712 */ 713 public SocketAddress getRemoteSocketAddress() { 714 if (!isConnected()) { 715 return null; 716 } 717 return new InetSocketAddress(getInetAddress(), getPort()); 718 } 719 720 /** 721 * Gets the bound local address and port of this socket. If the socket is 722 * unbound, {@code null} is returned. 723 * 724 * @return the local socket address. 725 */ 726 public SocketAddress getLocalSocketAddress() { 727 if (!isBound()) { 728 return null; 729 } 730 return new InetSocketAddress(getLocalAddress(), getLocalPort()); 731 } 732 733 /** 734 * Sets the socket option {@code SocketOptions.SO_REUSEADDR}. This option 735 * has to be enabled if more than one UDP socket wants to be bound to the 736 * same address. That could be needed for receiving multicast packets. 737 * <p> 738 * There is an undefined behavior if this option is set after the socket is 739 * already bound. 740 * 741 * @param reuse 742 * the socket option value to enable or disable this option. 743 * @throws SocketException 744 * if the socket is closed or the option could not be set. 745 */ 746 public void setReuseAddress(boolean reuse) throws SocketException { 747 checkClosedAndBind(false); 748 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse)); 749 } 750 751 /** 752 * Gets the state of the socket option {@code SocketOptions.SO_REUSEADDR}. 753 * 754 * @return {@code true} if the option is enabled, {@code false} otherwise. 755 * @throws SocketException 756 * if the socket is closed or the option is invalid. 757 */ 758 public boolean getReuseAddress() throws SocketException { 759 checkClosedAndBind(false); 760 return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)) 761 .booleanValue(); 762 } 763 764 /** 765 * Sets the socket option {@code SocketOptions.SO_BROADCAST}. This option 766 * must be enabled to send broadcast messages. 767 * 768 * @param broadcast 769 * the socket option value to enable or disable this option. 770 * @throws SocketException 771 * if the socket is closed or the option could not be set. 772 */ 773 public void setBroadcast(boolean broadcast) throws SocketException { 774 checkClosedAndBind(false); 775 impl.setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(broadcast)); 776 } 777 778 /** 779 * Gets the state of the socket option {@code SocketOptions.SO_BROADCAST}. 780 * 781 * @return {@code true} if the option is enabled, {@code false} otherwise. 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 * Sets the {@see SocketOptions#IP_TOS} value for every packet sent by this socket. 793 * 794 * @throws SocketException 795 * if the socket is closed or the option could not be set. 796 */ 797 public void setTrafficClass(int value) throws SocketException { 798 checkClosedAndBind(false); 799 if (value < 0 || value > 255) { 800 throw new IllegalArgumentException(); 801 } 802 impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value)); 803 } 804 805 /** 806 * Returns this socket's {@see SocketOptions#IP_TOS} setting. 807 * 808 * @throws SocketException 809 * if the socket is closed or the option is invalid. 810 */ 811 public int getTrafficClass() throws SocketException { 812 checkClosedAndBind(false); 813 return (Integer) impl.getOption(SocketOptions.IP_TOS); 814 } 815 816 /** 817 * Gets the state of this socket. 818 * 819 * @return {@code true} if the socket is closed, {@code false} otherwise. 820 */ 821 public boolean isClosed() { 822 return isClosed; 823 } 824 825 /** 826 * Gets the related DatagramChannel of this socket. This implementation 827 * returns always {@code null}. 828 * 829 * @return the related DatagramChannel or {@code null} if this socket was 830 * not created by a {@code DatagramChannel} object. 831 */ 832 public DatagramChannel getChannel() { 833 return null; 834 } 835} 836