Frames | No Frames |
1: /* ServerSocket.java -- Class for implementing server side sockets 2: Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: package java.net; 40: 41: import gnu.java.net.PlainSocketImpl; 42: 43: import java.io.IOException; 44: import java.nio.channels.IllegalBlockingModeException; 45: import java.nio.channels.ServerSocketChannel; 46: 47: 48: /* Written using on-line Java Platform 1.2 API Specification. 49: * Status: I believe all methods are implemented. 50: */ 51: 52: /** 53: * This class models server side sockets. The basic model is that the 54: * server socket is created and bound to some well known port. It then 55: * listens for and accepts connections. At that point the client and 56: * server sockets are ready to communicate with one another utilizing 57: * whatever application layer protocol they desire. 58: * 59: * As with the <code>Socket</code> class, most instance methods of this class 60: * simply redirect their calls to an implementation class. 61: * 62: * @author Aaron M. Renn (arenn@urbanophile.com) 63: * @author Per Bothner (bothner@cygnus.com) 64: */ 65: public class ServerSocket 66: { 67: /** 68: * This is the user defined SocketImplFactory, if one is supplied 69: */ 70: private static SocketImplFactory factory; 71: 72: /** 73: * This is the SocketImp object to which most instance methods in this 74: * class are redirected 75: */ 76: private SocketImpl impl; 77: 78: /** 79: * We need to retain the local address even after the socket is closed. 80: */ 81: private InetSocketAddress local; 82: private int port; 83: 84: /* 85: * This constructor is only used by java.nio. 86: */ 87: 88: ServerSocket(PlainSocketImpl impl) throws IOException 89: { 90: if (impl == null) 91: throw new NullPointerException("impl may not be null"); 92: 93: this.impl = impl; 94: this.impl.create(true); 95: setReuseAddress(true); 96: } 97: 98: /* 99: * This method is only used by java.nio. 100: */ 101: 102: SocketImpl getImpl() 103: { 104: return impl; 105: } 106: 107: /** 108: * Constructor that simply sets the implementation. 109: * 110: * @exception IOException If an error occurs 111: * 112: * @specnote This constructor is public since JDK 1.4 113: */ 114: public ServerSocket() throws IOException 115: { 116: if (factory != null) 117: impl = factory.createSocketImpl(); 118: else 119: impl = new PlainSocketImpl(); 120: 121: impl.create(true); 122: } 123: 124: /** 125: * Creates a server socket and binds it to the specified port. If the 126: * port number is 0, a random free port will be chosen. The pending 127: * connection queue on this socket will be set to 50. 128: * 129: * @param port The port number to bind to 130: * 131: * @exception IOException If an error occurs 132: * @exception SecurityException If a security manager exists and its 133: * checkListen method doesn't allow the operation 134: */ 135: public ServerSocket(int port) throws IOException 136: { 137: this(port, 50); 138: } 139: 140: /** 141: * Creates a server socket and binds it to the specified port. If the 142: * port number is 0, a random free port will be chosen. The pending 143: * connection queue on this socket will be set to the value passed as 144: * arg2. 145: * 146: * @param port The port number to bind to 147: * @param backlog The length of the pending connection queue 148: * 149: * @exception IOException If an error occurs 150: * @exception SecurityException If a security manager exists and its 151: * checkListen method doesn't allow the operation 152: */ 153: public ServerSocket(int port, int backlog) throws IOException 154: { 155: this(port, backlog, null); 156: } 157: 158: /** 159: * Creates a server socket and binds it to the specified port. If the 160: * port number is 0, a random free port will be chosen. The pending 161: * connection queue on this socket will be set to the value passed as 162: * backlog. The third argument specifies a particular local address to 163: * bind t or null to bind to all local address. 164: * 165: * @param port The port number to bind to 166: * @param backlog The length of the pending connection queue 167: * @param bindAddr The address to bind to, or null to bind to all addresses 168: * 169: * @exception IOException If an error occurs 170: * @exception SecurityException If a security manager exists and its 171: * checkListen method doesn't allow the operation 172: * 173: * @since 1.1 174: */ 175: public ServerSocket(int port, int backlog, InetAddress bindAddr) 176: throws IOException 177: { 178: this(); 179: 180: // bind/listen socket 181: bind(new InetSocketAddress(bindAddr, port), backlog); 182: } 183: 184: /** 185: * Binds the server socket to a specified socket address 186: * 187: * @param endpoint The socket address to bind to 188: * 189: * @exception IOException If an error occurs 190: * @exception IllegalArgumentException If address type is not supported 191: * @exception SecurityException If a security manager exists and its 192: * checkListen method doesn't allow the operation 193: * 194: * @since 1.4 195: */ 196: public void bind(SocketAddress endpoint) throws IOException 197: { 198: bind(endpoint, 50); 199: } 200: 201: /** 202: * Binds the server socket to a specified socket address 203: * 204: * @param endpoint The socket address to bind to 205: * @param backlog The length of the pending connection queue 206: * 207: * @exception IOException If an error occurs 208: * @exception IllegalArgumentException If address type is not supported 209: * @exception SecurityException If a security manager exists and its 210: * checkListen method doesn't allow the operation 211: * 212: * @since 1.4 213: */ 214: public void bind(SocketAddress endpoint, int backlog) 215: throws IOException 216: { 217: if (isClosed()) 218: throw new SocketException("ServerSocket is closed"); 219: 220: if (isBound()) 221: throw new SocketException("Already bound"); 222: 223: InetAddress addr; 224: int port; 225: 226: if (endpoint == null) 227: { 228: addr = InetAddress.ANY_IF; 229: port = 0; 230: } 231: else if (! (endpoint instanceof InetSocketAddress)) 232: { 233: throw new IllegalArgumentException("Address type not supported"); 234: } 235: else 236: { 237: InetSocketAddress tmp = (InetSocketAddress) endpoint; 238: if (tmp.isUnresolved()) 239: throw new SocketException("Unresolved address"); 240: addr = tmp.getAddress(); 241: port = tmp.getPort(); 242: } 243: 244: SecurityManager s = System.getSecurityManager(); 245: if (s != null) 246: s.checkListen(port); 247: 248: try 249: { 250: impl.bind(addr, port); 251: impl.listen(backlog); 252: this.port = port; 253: local = new InetSocketAddress( 254: (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR), 255: impl.getLocalPort()); 256: } 257: finally 258: { 259: try 260: { 261: if (local == null) 262: close(); 263: } 264: catch (IOException _) 265: { 266: } 267: } 268: } 269: 270: /** 271: * This method returns the local address to which this socket is bound 272: * 273: * @return The socket's local address 274: */ 275: public InetAddress getInetAddress() 276: { 277: if (local == null) 278: return null; 279: 280: return local.getAddress(); 281: } 282: 283: /** 284: * This method returns the local port number to which this socket is bound 285: * 286: * @return The socket's port number 287: */ 288: public int getLocalPort() 289: { 290: if (local == null) 291: return -1; 292: 293: return local.getPort(); 294: } 295: 296: /** 297: * Returns the local socket address 298: * 299: * @return the local socket address, null if not bound 300: * 301: * @since 1.4 302: */ 303: public SocketAddress getLocalSocketAddress() 304: { 305: return local; 306: } 307: 308: /** 309: * Accepts a new connection and returns a connected <code>Socket</code> 310: * instance representing that connection. This method will block until a 311: * connection is available. 312: * 313: * @return socket object for the just accepted connection 314: * 315: * @exception IOException If an error occurs 316: * @exception SecurityException If a security manager exists and its 317: * checkListen method doesn't allow the operation 318: * @exception IllegalBlockingModeException If this socket has an associated 319: * channel, and the channel is in non-blocking mode 320: * @exception SocketTimeoutException If a timeout was previously set with 321: * setSoTimeout and the timeout has been reached 322: */ 323: public Socket accept() throws IOException 324: { 325: Socket socket = new Socket(); 326: 327: try 328: { 329: implAccept(socket); 330: } 331: catch (IOException e) 332: { 333: try 334: { 335: socket.close(); 336: } 337: catch (IOException e2) 338: { 339: // Ignore. 340: } 341: 342: throw e; 343: } 344: catch (SecurityException e) 345: { 346: try 347: { 348: socket.close(); 349: } 350: catch (IOException e2) 351: { 352: // Ignore. 353: } 354: 355: throw e; 356: } 357: 358: return socket; 359: } 360: 361: /** 362: * This protected method is used to help subclasses override 363: * <code>ServerSocket.accept()</code>. The passed in socket will be 364: * connected when this method returns. 365: * 366: * @param socket The socket that is used for the accepted connection 367: * 368: * @exception IOException If an error occurs 369: * @exception IllegalBlockingModeException If this socket has an associated 370: * channel, and the channel is in non-blocking mode 371: * 372: * @since 1.1 373: */ 374: protected final void implAccept(Socket socket) throws IOException 375: { 376: if (isClosed()) 377: throw new SocketException("ServerSocket is closed"); 378: 379: // The Sun spec says that if we have an associated channel and 380: // it is in non-blocking mode, we throw an IllegalBlockingModeException. 381: // However, in our implementation if the channel itself initiated this 382: // operation, then we must honor it regardless of its blocking mode. 383: if (getChannel() != null && ! getChannel().isBlocking() 384: && ! ((PlainSocketImpl) getImpl()).isInChannelOperation()) 385: throw new IllegalBlockingModeException(); 386: 387: impl.accept(socket.impl); 388: socket.bound = true; 389: socket.implCreated = true; 390: 391: SecurityManager sm = System.getSecurityManager(); 392: if (sm != null) 393: sm.checkAccept(socket.getInetAddress().getHostAddress(), 394: socket.getPort()); 395: } 396: 397: /** 398: * Closes this socket and stops listening for connections 399: * 400: * @exception IOException If an error occurs 401: */ 402: public void close() throws IOException 403: { 404: if (impl != null) 405: { 406: impl.close(); 407: impl = null; 408: } 409: } 410: 411: /** 412: * Returns the unique <code>ServerSocketChannel</code> object 413: * associated with this socket, if any. 414: * 415: * <p>The socket only has a <code>ServerSocketChannel</code> if its created 416: * by <code>ServerSocketChannel.open()</code>.</p> 417: * 418: * @return the associated socket channel, null if none exists 419: * 420: * @since 1.4 421: */ 422: public ServerSocketChannel getChannel() 423: { 424: return null; 425: } 426: 427: /** 428: * Returns true when the socket is bound, otherwise false 429: * 430: * @return true if socket is bound, false otherwise 431: * 432: * @since 1.4 433: */ 434: public boolean isBound() 435: { 436: return local != null; 437: } 438: 439: /** 440: * Returns true if the socket is closed, otherwise false 441: * 442: * @return true if socket is closed, false otherwise 443: * 444: * @since 1.4 445: */ 446: public boolean isClosed() 447: { 448: ServerSocketChannel channel = getChannel(); 449: return impl == null || (channel != null && ! channel.isOpen()); 450: } 451: 452: /** 453: * Sets the value of SO_TIMEOUT. A value of 0 implies that SO_TIMEOUT is 454: * disabled (ie, operations never time out). This is the number of 455: * milliseconds a socket operation can block before an 456: * InterruptedIOException is thrown. 457: * 458: * @param timeout The new SO_TIMEOUT value 459: * 460: * @exception SocketException If an error occurs 461: * 462: * @since 1.1 463: */ 464: public void setSoTimeout(int timeout) throws SocketException 465: { 466: if (isClosed()) 467: throw new SocketException("ServerSocket is closed"); 468: 469: if (timeout < 0) 470: throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0"); 471: 472: impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 473: } 474: 475: /** 476: * Retrieves the current value of the SO_TIMEOUT setting. A value of 0 477: * implies that SO_TIMEOUT is disabled (ie, operations never time out). 478: * This is the number of milliseconds a socket operation can block before 479: * an InterruptedIOException is thrown. 480: * 481: * @return The value of SO_TIMEOUT 482: * 483: * @exception IOException If an error occurs 484: * 485: * @since 1.1 486: */ 487: public int getSoTimeout() throws IOException 488: { 489: if (isClosed()) 490: throw new SocketException("ServerSocket is closed"); 491: 492: Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT); 493: 494: if (! (timeout instanceof Integer)) 495: throw new IOException("Internal Error"); 496: 497: return ((Integer) timeout).intValue(); 498: } 499: 500: /** 501: * Enables/Disables the SO_REUSEADDR option 502: * 503: * @param on true if SO_REUSEADDR should be enabled, false otherwise 504: * 505: * @exception SocketException If an error occurs 506: * 507: * @since 1.4 508: */ 509: public void setReuseAddress(boolean on) throws SocketException 510: { 511: if (isClosed()) 512: throw new SocketException("ServerSocket is closed"); 513: 514: impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); 515: } 516: 517: /** 518: * Checks if the SO_REUSEADDR option is enabled 519: * 520: * @return true if SO_REUSEADDR is set, false otherwise 521: * 522: * @exception SocketException If an error occurs 523: * 524: * @since 1.4 525: */ 526: public boolean getReuseAddress() throws SocketException 527: { 528: if (isClosed()) 529: throw new SocketException("ServerSocket is closed"); 530: 531: Object reuseaddr = impl.getOption(SocketOptions.SO_REUSEADDR); 532: 533: if (! (reuseaddr instanceof Boolean)) 534: throw new SocketException("Internal Error"); 535: 536: return ((Boolean) reuseaddr).booleanValue(); 537: } 538: 539: /** 540: * This method sets the value for the system level socket option 541: * SO_RCVBUF to the specified value. Note that valid values for this 542: * option are specific to a given operating system. 543: * 544: * @param size The new receive buffer size. 545: * 546: * @exception SocketException If an error occurs or Socket is not connected 547: * @exception IllegalArgumentException If size is 0 or negative 548: * 549: * @since 1.4 550: */ 551: public void setReceiveBufferSize(int size) throws SocketException 552: { 553: if (isClosed()) 554: throw new SocketException("ServerSocket is closed"); 555: 556: if (size <= 0) 557: throw new IllegalArgumentException("SO_RCVBUF value must be > 0"); 558: 559: impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 560: } 561: 562: /** 563: * This method returns the value of the system level socket option 564: * SO_RCVBUF, which is used by the operating system to tune buffer 565: * sizes for data transfers. 566: * 567: * @return The receive buffer size. 568: * 569: * @exception SocketException If an error occurs or Socket is not connected 570: * 571: * @since 1.4 572: */ 573: public int getReceiveBufferSize() throws SocketException 574: { 575: if (isClosed()) 576: throw new SocketException("ServerSocket is closed"); 577: 578: Object buf = impl.getOption(SocketOptions.SO_RCVBUF); 579: 580: if (! (buf instanceof Integer)) 581: throw new SocketException("Internal Error: Unexpected type"); 582: 583: return ((Integer) buf).intValue(); 584: } 585: 586: /** 587: * Returns the value of this socket as a <code>String</code>. 588: * 589: * @return This socket represented as a <code>String</code>. 590: */ 591: public String toString() 592: { 593: if (! isBound()) 594: return "ServerSocket[unbound]"; 595: 596: return ("ServerSocket[addr=" + getInetAddress() + ",port=" 597: + port + ",localport=" + getLocalPort() + "]"); 598: } 599: 600: /** 601: * Sets the <code>SocketImplFactory</code> for all 602: * <code>ServerSocket</code>'s. This may only be done 603: * once per virtual machine. Subsequent attempts will generate an 604: * exception. Note that a <code>SecurityManager</code> check is made prior 605: * to setting the factory. If insufficient privileges exist to set the 606: * factory, an exception will be thrown 607: * 608: * @param fac the factory to set 609: * 610: * @exception SecurityException If this operation is not allowed by the 611: * <code>SecurityManager</code>. 612: * @exception SocketException If the factory object is already defined 613: * @exception IOException If any other error occurs 614: */ 615: public static synchronized void setSocketFactory(SocketImplFactory fac) 616: throws IOException 617: { 618: if (factory != null) 619: throw new SocketException("SocketFactory already defined"); 620: 621: SecurityManager sm = System.getSecurityManager(); 622: if (sm != null) 623: sm.checkSetFactory(); 624: 625: factory = fac; 626: } 627: }