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