GNU Classpath (0.20) | |
Frames | No Frames |
1: /* ServerSocket.java -- Class for implementing server side sockets 2: Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 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: 83: /* 84: * This constructor is only used by java.nio. 85: */ 86: 87: // FIXME: Workaround a bug in gcj. 88: //ServerSocket (PlainSocketImpl impl) throws IOException 89: ServerSocket(SocketImpl impl) throws IOException 90: { 91: if (impl == null) 92: throw new NullPointerException("impl may not be null"); 93: 94: this.impl = impl; 95: this.impl.create(true); 96: } 97: 98: /* 99: * This method is only used by java.nio. 100: */ 101: 102: // FIXME: Workaround a bug in gcj. 103: //PlainSocketImpl getImpl() 104: SocketImpl getImpl() 105: { 106: return impl; 107: } 108: 109: /** 110: * Constructor that simply sets the implementation. 111: * 112: * @exception IOException If an error occurs 113: * 114: * @specnote This constructor is public since JDK 1.4 115: */ 116: public ServerSocket() throws IOException 117: { 118: if (factory != null) 119: impl = factory.createSocketImpl(); 120: else 121: impl = new PlainSocketImpl(); 122: 123: impl.create(true); 124: } 125: 126: /** 127: * Creates a server socket and binds it to the specified port. If the 128: * port number is 0, a random free port will be chosen. The pending 129: * connection queue on this socket will be set to 50. 130: * 131: * @param port The port number to bind to 132: * 133: * @exception IOException If an error occurs 134: * @exception SecurityException If a security manager exists and its 135: * checkListen method doesn't allow the operation 136: */ 137: public ServerSocket(int port) throws IOException 138: { 139: this(port, 50); 140: } 141: 142: /** 143: * Creates a server socket and binds it to the specified port. If the 144: * port number is 0, a random free port will be chosen. The pending 145: * connection queue on this socket will be set to the value passed as 146: * arg2. 147: * 148: * @param port The port number to bind to 149: * @param backlog The length of the pending connection queue 150: * 151: * @exception IOException If an error occurs 152: * @exception SecurityException If a security manager exists and its 153: * checkListen method doesn't allow the operation 154: */ 155: public ServerSocket(int port, int backlog) throws IOException 156: { 157: this(port, backlog, null); 158: } 159: 160: /** 161: * Creates a server socket and binds it to the specified port. If the 162: * port number is 0, a random free port will be chosen. The pending 163: * connection queue on this socket will be set to the value passed as 164: * backlog. The third argument specifies a particular local address to 165: * bind t or null to bind to all local address. 166: * 167: * @param port The port number to bind to 168: * @param backlog The length of the pending connection queue 169: * @param bindAddr The address to bind to, or null to bind to all addresses 170: * 171: * @exception IOException If an error occurs 172: * @exception SecurityException If a security manager exists and its 173: * checkListen method doesn't allow the operation 174: * 175: * @since 1.1 176: */ 177: public ServerSocket(int port, int backlog, InetAddress bindAddr) 178: throws IOException 179: { 180: this(); 181: 182: // bind/listen socket 183: bind(new InetSocketAddress(bindAddr, port), backlog); 184: } 185: 186: /** 187: * Binds the server socket to a specified socket address 188: * 189: * @param endpoint The socket address to bind to 190: * 191: * @exception IOException If an error occurs 192: * @exception IllegalArgumentException If address type is not supported 193: * @exception SecurityException If a security manager exists and its 194: * checkListen method doesn't allow the operation 195: * 196: * @since 1.4 197: */ 198: public void bind(SocketAddress endpoint) throws IOException 199: { 200: bind(endpoint, 50); 201: } 202: 203: /** 204: * Binds the server socket to a specified socket address 205: * 206: * @param endpoint The socket address to bind to 207: * @param backlog The length of the pending connection queue 208: * 209: * @exception IOException If an error occurs 210: * @exception IllegalArgumentException If address type is not supported 211: * @exception SecurityException If a security manager exists and its 212: * checkListen method doesn't allow the operation 213: * 214: * @since 1.4 215: */ 216: public void bind(SocketAddress endpoint, int backlog) 217: throws IOException 218: { 219: if (isClosed()) 220: throw new SocketException("ServerSocket is closed"); 221: 222: if (! (endpoint instanceof InetSocketAddress)) 223: throw new IllegalArgumentException("Address type not supported"); 224: 225: InetSocketAddress tmp = (InetSocketAddress) endpoint; 226: 227: SecurityManager s = System.getSecurityManager(); 228: if (s != null) 229: s.checkListen(tmp.getPort()); 230: 231: InetAddress addr = tmp.getAddress(); 232: 233: // Initialize addr with 0.0.0.0. 234: if (addr == null) 235: addr = InetAddress.ANY_IF; 236: 237: try 238: { 239: impl.bind(addr, tmp.getPort()); 240: impl.listen(backlog); 241: local = new InetSocketAddress( 242: (InetAddress) impl.getOption(SocketOptions.SO_BINDADDR), 243: impl.getLocalPort()); 244: } 245: catch (IOException exception) 246: { 247: close(); 248: throw exception; 249: } 250: catch (RuntimeException exception) 251: { 252: close(); 253: throw exception; 254: } 255: catch (Error error) 256: { 257: close(); 258: throw error; 259: } 260: } 261: 262: /** 263: * This method returns the local address to which this socket is bound 264: * 265: * @return The socket's local address 266: */ 267: public InetAddress getInetAddress() 268: { 269: if (local == null) 270: return null; 271: 272: return local.getAddress(); 273: } 274: 275: /** 276: * This method returns the local port number to which this socket is bound 277: * 278: * @return The socket's port number 279: */ 280: public int getLocalPort() 281: { 282: if (local == null) 283: return -1; 284: 285: return local.getPort(); 286: } 287: 288: /** 289: * Returns the local socket address 290: * 291: * @return the local socket address, null if not bound 292: * 293: * @since 1.4 294: */ 295: public SocketAddress getLocalSocketAddress() 296: { 297: return local; 298: } 299: 300: /** 301: * Accepts a new connection and returns a connected <code>Socket</code> 302: * instance representing that connection. This method will block until a 303: * connection is available. 304: * 305: * @return socket object for the just accepted connection 306: * 307: * @exception IOException If an error occurs 308: * @exception SecurityException If a security manager exists and its 309: * checkListen method doesn't allow the operation 310: * @exception IllegalBlockingModeException If this socket has an associated 311: * channel, and the channel is in non-blocking mode 312: * @exception SocketTimeoutException If a timeout was previously set with 313: * setSoTimeout and the timeout has been reached 314: */ 315: public Socket accept() throws IOException 316: { 317: SecurityManager sm = System.getSecurityManager(); 318: if (sm != null) 319: sm.checkAccept(impl.getInetAddress().getHostAddress(), 320: impl.getLocalPort()); 321: 322: Socket socket = new Socket(); 323: 324: try 325: { 326: implAccept(socket); 327: } 328: catch (IOException e) 329: { 330: try 331: { 332: socket.close(); 333: } 334: catch (IOException e2) 335: { 336: // Ignore. 337: } 338: 339: throw e; 340: } 341: 342: return socket; 343: } 344: 345: /** 346: * This protected method is used to help subclasses override 347: * <code>ServerSocket.accept()</code>. The passed in socket will be 348: * connected when this method returns. 349: * 350: * @param socket The socket that is used for the accepted connection 351: * 352: * @exception IOException If an error occurs 353: * @exception IllegalBlockingModeException If this socket has an associated 354: * channel, and the channel is in non-blocking mode 355: * 356: * @since 1.1 357: */ 358: protected final void implAccept(Socket socket) throws IOException 359: { 360: if (isClosed()) 361: throw new SocketException("ServerSocket is closed"); 362: 363: // The Sun spec says that if we have an associated channel and 364: // it is in non-blocking mode, we throw an IllegalBlockingModeException. 365: // However, in our implementation if the channel itself initiated this 366: // operation, then we must honor it regardless of its blocking mode. 367: if (getChannel() != null && ! getChannel().isBlocking() 368: && ! ((PlainSocketImpl) getImpl()).isInChannelOperation()) 369: throw new IllegalBlockingModeException(); 370: 371: impl.accept(socket.impl); 372: socket.implCreated = true; 373: socket.bound = true; 374: } 375: 376: /** 377: * Closes this socket and stops listening for connections 378: * 379: * @exception IOException If an error occurs 380: */ 381: public void close() throws IOException 382: { 383: if (isClosed()) 384: return; 385: 386: impl.close(); 387: impl = null; 388: 389: if (getChannel() != null) 390: getChannel().close(); 391: } 392: 393: /** 394: * Returns the unique <code>ServerSocketChannel</code> object 395: * associated with this socket, if any. 396: * 397: * <p>The socket only has a <code>ServerSocketChannel</code> if its created 398: * by <code>ServerSocketChannel.open()</code>.</p> 399: * 400: * @return the associated socket channel, null if none exists 401: * 402: * @since 1.4 403: */ 404: public ServerSocketChannel getChannel() 405: { 406: return null; 407: } 408: 409: /** 410: * Returns true when the socket is bound, otherwise false 411: * 412: * @return true if socket is bound, false otherwise 413: * 414: * @since 1.4 415: */ 416: public boolean isBound() 417: { 418: return local != null; 419: } 420: 421: /** 422: * Returns true if the socket is closed, otherwise false 423: * 424: * @return true if socket is closed, false otherwise 425: * 426: * @since 1.4 427: */ 428: public boolean isClosed() 429: { 430: return impl == null; 431: } 432: 433: /** 434: * Sets the value of SO_TIMEOUT. A value of 0 implies that SO_TIMEOUT is 435: * disabled (ie, operations never time out). This is the number of 436: * milliseconds a socket operation can block before an 437: * InterruptedIOException is thrown. 438: * 439: * @param timeout The new SO_TIMEOUT value 440: * 441: * @exception SocketException If an error occurs 442: * 443: * @since 1.1 444: */ 445: public void setSoTimeout(int timeout) throws SocketException 446: { 447: if (isClosed()) 448: throw new SocketException("ServerSocket is closed"); 449: 450: if (timeout < 0) 451: throw new IllegalArgumentException("SO_TIMEOUT value must be >= 0"); 452: 453: impl.setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); 454: } 455: 456: /** 457: * Retrieves the current value of the SO_TIMEOUT setting. A value of 0 458: * implies that SO_TIMEOUT is disabled (ie, operations never time out). 459: * This is the number of milliseconds a socket operation can block before 460: * an InterruptedIOException is thrown. 461: * 462: * @return The value of SO_TIMEOUT 463: * 464: * @exception IOException If an error occurs 465: * 466: * @since 1.1 467: */ 468: public int getSoTimeout() throws IOException 469: { 470: if (isClosed()) 471: throw new SocketException("ServerSocket is closed"); 472: 473: Object timeout = impl.getOption(SocketOptions.SO_TIMEOUT); 474: 475: if (! (timeout instanceof Integer)) 476: throw new IOException("Internal Error"); 477: 478: return ((Integer) timeout).intValue(); 479: } 480: 481: /** 482: * Enables/Disables the SO_REUSEADDR option 483: * 484: * @param on true if SO_REUSEADDR should be enabled, false otherwise 485: * 486: * @exception SocketException If an error occurs 487: * 488: * @since 1.4 489: */ 490: public void setReuseAddress(boolean on) throws SocketException 491: { 492: if (isClosed()) 493: throw new SocketException("ServerSocket is closed"); 494: 495: impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); 496: } 497: 498: /** 499: * Checks if the SO_REUSEADDR option is enabled 500: * 501: * @return true if SO_REUSEADDR is set, false otherwise 502: * 503: * @exception SocketException If an error occurs 504: * 505: * @since 1.4 506: */ 507: public boolean getReuseAddress() throws SocketException 508: { 509: if (isClosed()) 510: throw new SocketException("ServerSocket is closed"); 511: 512: Object reuseaddr = impl.getOption(SocketOptions.SO_REUSEADDR); 513: 514: if (! (reuseaddr instanceof Boolean)) 515: throw new SocketException("Internal Error"); 516: 517: return ((Boolean) reuseaddr).booleanValue(); 518: } 519: 520: /** 521: * This method sets the value for the system level socket option 522: * SO_RCVBUF to the specified value. Note that valid values for this 523: * option are specific to a given operating system. 524: * 525: * @param size The new receive buffer size. 526: * 527: * @exception SocketException If an error occurs or Socket is not connected 528: * @exception IllegalArgumentException If size is 0 or negative 529: * 530: * @since 1.4 531: */ 532: public void setReceiveBufferSize(int size) throws SocketException 533: { 534: if (isClosed()) 535: throw new SocketException("ServerSocket is closed"); 536: 537: if (size <= 0) 538: throw new IllegalArgumentException("SO_RCVBUF value must be > 0"); 539: 540: impl.setOption(SocketOptions.SO_RCVBUF, new Integer(size)); 541: } 542: 543: /** 544: * This method returns the value of the system level socket option 545: * SO_RCVBUF, which is used by the operating system to tune buffer 546: * sizes for data transfers. 547: * 548: * @return The receive buffer size. 549: * 550: * @exception SocketException If an error occurs or Socket is not connected 551: * 552: * @since 1.4 553: */ 554: public int getReceiveBufferSize() throws SocketException 555: { 556: if (isClosed()) 557: throw new SocketException("ServerSocket is closed"); 558: 559: Object buf = impl.getOption(SocketOptions.SO_RCVBUF); 560: 561: if (! (buf instanceof Integer)) 562: throw new SocketException("Internal Error: Unexpected type"); 563: 564: return ((Integer) buf).intValue(); 565: } 566: 567: /** 568: * Returns the value of this socket as a <code>String</code>. 569: * 570: * @return This socket represented as a <code>String</code>. 571: */ 572: public String toString() 573: { 574: if (! isBound()) 575: return "ServerSocket[unbound]"; 576: 577: return ("ServerSocket[addr=" + getInetAddress() + ",port=" 578: + impl.getPort() + ",localport=" + impl.getLocalPort() + "]"); 579: } 580: 581: /** 582: * Sets the <code>SocketImplFactory</code> for all 583: * <code>ServerSocket</code>'s. This may only be done 584: * once per virtual machine. Subsequent attempts will generate an 585: * exception. Note that a <code>SecurityManager</code> check is made prior 586: * to setting the factory. If insufficient privileges exist to set the 587: * factory, an exception will be thrown 588: * 589: * @param fac the factory to set 590: * 591: * @exception SecurityException If this operation is not allowed by the 592: * <code>SecurityManager</code>. 593: * @exception SocketException If the factory object is already defined 594: * @exception IOException If any other error occurs 595: */ 596: public static synchronized void setSocketFactory(SocketImplFactory fac) 597: throws IOException 598: { 599: factory = fac; 600: } 601: }
GNU Classpath (0.20) |