001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.net;
019:
020: import java.io.IOException;
021: import java.nio.channels.ServerSocketChannel;
022:
023: import org.apache.harmony.luni.net.SocketImplProvider;
024: import org.apache.harmony.luni.platform.Platform;
025:
026: import org.apache.harmony.luni.util.Msg;
027:
028: /**
029: * ServerSocket create connections between 'host' and 'client' machines. The
030: * ServerSocket listens on a well known port and upon a connection request,
031: * instantiates a 'host' sockets, which carries on future communication with the
032: * requesting 'client' socket, so that the server socket may continue listening
033: * for connection requests. They are passive objects, having no execution thread
034: * of their own to listen on.
035: */
036: public class ServerSocket {
037:
038: SocketImpl impl;
039:
040: static SocketImplFactory factory;
041:
042: private volatile boolean isCreated;
043:
044: private boolean isBound;
045:
046: private boolean isClosed;
047:
048: static {
049: Platform.getNetworkSystem().oneTimeInitialization(true);
050: }
051:
052: /**
053: * Construct a ServerSocket, which is not bound to any port. The default
054: * number of pending connections may be backlogged.
055: *
056: * @see Socket
057: */
058: public ServerSocket() throws IOException {
059: impl = factory != null ? factory.createSocketImpl()
060: : SocketImplProvider.getServerSocketImpl();
061: }
062:
063: protected ServerSocket(SocketImpl impl) {
064: this .impl = impl;
065: }
066:
067: /**
068: * Construct a ServerSocket, bound to the nominated port on the default
069: * localhost. The default number of pending connections may be backlogged.
070: *
071: * @param aport
072: * the port number to listen for connection requests on
073: * @see Socket
074: */
075: public ServerSocket(int aport) throws IOException {
076: this (aport, defaultBacklog(), InetAddress.ANY);
077: }
078:
079: /**
080: * Construct a ServerSocket, bound to the nominated port on the default
081: * localhost. The number of pending connections that may be backlogged is a
082: * specified.
083: *
084: * @param aport
085: * the port number to listen for connection requests on
086: * @param backlog
087: * the number of pending connection requests, before requests are
088: * rejected
089: * @see Socket
090: */
091: public ServerSocket(int aport, int backlog) throws IOException {
092: this (aport, backlog, InetAddress.ANY);
093: }
094:
095: /**
096: * Construct a ServerSocket, bound to the nominated local host/port. The
097: * number of pending connections that may be backlogged is a specified.
098: *
099: * @param aport
100: * the port number to listen for connection requests on
101: * @param localAddr
102: * the local machine address to bind on
103: * @param backlog
104: * the number of pending connection requests, before requests are
105: * rejected
106: * @see Socket
107: */
108: public ServerSocket(int aport, int backlog, InetAddress localAddr)
109: throws IOException {
110: super ();
111: checkListen(aport);
112: impl = factory != null ? factory.createSocketImpl()
113: : SocketImplProvider.getServerSocketImpl();
114: InetAddress addr = localAddr == null ? InetAddress.ANY
115: : localAddr;
116:
117: synchronized (this ) {
118: impl.create(true);
119: isCreated = true;
120: try {
121: impl.bind(addr, aport);
122: isBound = true;
123: impl.listen(backlog > 0 ? backlog : defaultBacklog());
124: } catch (IOException e) {
125: close();
126: throw e;
127: }
128: }
129: }
130:
131: /**
132: * Retrieve the first connection request and answer the 'host' socket that
133: * will conduct further communications with the requesting 'client' socket.
134: *
135: * @return Socket the 'host' socket
136: * @exception IOException
137: * if an error occurs while instantiating the 'host' socket
138: */
139: public Socket accept() throws IOException {
140: checkClosedAndCreate(false);
141: if (!isBound()) {
142: throw new SocketException(Msg.getString("K031f")); //$NON-NLS-1$
143: }
144:
145: Socket aSocket = new Socket();
146: try {
147: synchronized (this ) {
148: implAccept(aSocket);
149: }
150: SecurityManager security = System.getSecurityManager();
151: if (security != null) {
152: security.checkAccept(aSocket.getInetAddress()
153: .getHostAddress(), aSocket.getPort());
154: }
155: } catch (SecurityException e) {
156: aSocket.close();
157: throw e;
158: } catch (IOException e) {
159: aSocket.close();
160: throw e;
161: }
162: return aSocket;
163: }
164:
165: /**
166: * Check whether the server may listen for connection requests on
167: * <code>aport</code>. Throw an exception if the port is outside the
168: * valid range or does not satisfy the security policy.
169: *
170: * @param aPort
171: * the candidate port to listen on
172: */
173: void checkListen(int aPort) {
174: if (aPort < 0 || aPort > 65535) {
175: throw new IllegalArgumentException(Msg.getString(
176: "K0325", aPort)); //$NON-NLS-1$
177: }
178: SecurityManager security = System.getSecurityManager();
179: if (security != null) {
180: security.checkListen(aPort);
181: }
182: }
183:
184: /**
185: * Close this server socket. Any attempt to connect to this socket
186: * thereafter will fail.
187: */
188: public void close() throws IOException {
189: isClosed = true;
190: impl.close();
191: }
192:
193: /**
194: * Answer the default number of pending connections on a server socket.
195: *
196: * @return int the default number of pending connection requests
197: */
198: static int defaultBacklog() {
199: return 50;
200: }
201:
202: /**
203: * Answer the local IP address for this server socket. Return null if the
204: * socket is not bound. This is useful on multihomed hosts.
205: *
206: * @return InetAddress the local address
207: */
208: public InetAddress getInetAddress() {
209: if (!isBound()) {
210: return null;
211: }
212: return impl.getInetAddress();
213: }
214:
215: /**
216: * Answer the local port for this server socket. Return -1 if the socket is
217: * not bound.
218: *
219: * @return int the local port the server is listening on
220: */
221: public int getLocalPort() {
222: if (!isBound()) {
223: return -1;
224: }
225: return impl.getLocalPort();
226: }
227:
228: /**
229: * Answer the time-out period of this server socket. This is the time the
230: * server will wait listening for connections, before exiting.
231: *
232: * @return int the listening timeout
233: * @exception SocketException
234: * thrown if option cannot be retrieved
235: */
236: public synchronized int getSoTimeout() throws IOException {
237: if (!isCreated) {
238: synchronized (this ) {
239: if (!isCreated) {
240: try {
241: impl.create(true);
242: } catch (SocketException e) {
243: throw e;
244: } catch (IOException e) {
245: throw new SocketException(e.toString());
246: }
247: isCreated = true;
248: }
249: }
250: }
251: return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT))
252: .intValue();
253: }
254:
255: /**
256: * Invoke the server socket implementation to accept a connection on the
257: * newly created <code>aSocket</code>.
258: *
259: * @param aSocket
260: * the concrete socketImpl to accept the connection request on
261: * @exception IOException
262: * thrown if connection cannot be accepted
263: */
264: protected final void implAccept(Socket aSocket) throws IOException {
265: impl.accept(aSocket.impl);
266: aSocket.accepted();
267: }
268:
269: /**
270: * Set the server socket implementation factory. This method may only be
271: * invoked with sufficient security and only once during the application
272: * lifetime.
273: *
274: * @param aFactory
275: * the streaming socket factory to be used for further socket
276: * instantiations
277: * @exception IOException
278: * thrown if the factory is already set
279: */
280: public static synchronized void setSocketFactory(
281: SocketImplFactory aFactory) throws IOException {
282: SecurityManager security = System.getSecurityManager();
283: if (security != null) {
284: security.checkSetFactory();
285: }
286: if (factory != null) {
287: throw new SocketException(Msg.getString("K0042")); //$NON-NLS-1$
288: }
289: factory = aFactory;
290: }
291:
292: /**
293: * Set the listen time-out period for this server socket.
294: *
295: * @param timeout
296: * the time to wait for a connection request
297: * @exception SocketException
298: * thrown if an error occurs during setting the option
299: */
300: public synchronized void setSoTimeout(int timeout)
301: throws SocketException {
302: checkClosedAndCreate(true);
303: if (timeout < 0) {
304: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
305: }
306: impl.setOption(SocketOptions.SO_TIMEOUT, Integer
307: .valueOf(timeout));
308: }
309:
310: /**
311: * Answers a string containing a concise, human-readable description of the
312: * server socket. The <code>port</code> field is reported a zero, as there
313: * is no connection formed to the server.
314: *
315: * @return String the description
316: */
317: @Override
318: public String toString() {
319: StringBuffer result = new StringBuffer(64);
320: result.append("ServerSocket["); //$NON-NLS-1$
321: if (!isBound()) {
322: return result.append("unbound]").toString(); //$NON-NLS-1$
323: }
324: return result.append("addr=") //$NON-NLS-1$
325: .append(getInetAddress().getHostName()).append("/") //$NON-NLS-1$
326: .append(getInetAddress().getHostAddress()).append(
327: ",port=0,localport=") //$NON-NLS-1$
328: .append(getLocalPort()).append("]") //$NON-NLS-1$
329: .toString();
330: }
331:
332: /**
333: * Bind the ServerSocket to the nominated local host/port. The default
334: * number of pending connections may be backlogged.
335: *
336: * @param localAddr
337: * the local machine address and port to bind on
338: *
339: * @exception IllegalArgumentException
340: * if the SocketAddress is not supported
341: * @exception IOException
342: * if the socket is already bound, or a problem occurs during
343: * the bind
344: */
345: public void bind(SocketAddress localAddr) throws IOException {
346: bind(localAddr, defaultBacklog());
347: }
348:
349: /**
350: * Bind the ServerSocket to the nominated local host/port. The number of
351: * pending connections that may be backlogged is a specified.
352: *
353: * @param localAddr
354: * the local machine address and port to bind on
355: * @param backlog
356: * the number of pending connection requests, before requests are
357: * rejected
358: *
359: * @exception IllegalArgumentException
360: * if the SocketAddress is not supported
361: * @exception IOException
362: * if the socket is already bound, or a problem occurs during
363: * the bind
364: */
365: public void bind(SocketAddress localAddr, int backlog)
366: throws IOException {
367: checkClosedAndCreate(true);
368: if (isBound()) {
369: throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$
370: }
371: int port = 0;
372: InetAddress addr = InetAddress.ANY;
373: if (localAddr != null) {
374: if (!(localAddr instanceof InetSocketAddress)) {
375: throw new IllegalArgumentException(Msg.getString(
376: "K0316", localAddr.getClass())); //$NON-NLS-1$
377: }
378: InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
379: if ((addr = inetAddr.getAddress()) == null) {
380: throw new SocketException(Msg.getString(
381: "K0317", inetAddr.getHostName())); //$NON-NLS-1$
382: }
383: port = inetAddr.getPort();
384: }
385: SecurityManager security = System.getSecurityManager();
386: if (security != null) {
387: security.checkListen(port);
388: }
389:
390: synchronized (this ) {
391: try {
392: impl.bind(addr, port);
393: isBound = true;
394: impl.listen(backlog > 0 ? backlog : defaultBacklog());
395: } catch (IOException e) {
396: close();
397: throw e;
398: }
399: }
400: }
401:
402: /**
403: * Answer the local SocketAddress for this server socket, or null if the
404: * socket is not bound. This is useful on multihomed hosts.
405: */
406: public SocketAddress getLocalSocketAddress() {
407: if (!isBound()) {
408: return null;
409: }
410: return new InetSocketAddress(getInetAddress(), getLocalPort());
411: }
412:
413: /**
414: * Return if the server socket is bound to a local address and port.
415: */
416: public boolean isBound() {
417: return isBound;
418: }
419:
420: /**
421: * Return if the server socket is closed.
422: */
423: public boolean isClosed() {
424: return isClosed;
425: }
426:
427: /**
428: * Check if the socket is closed, and throw an exception.
429: */
430: private void checkClosedAndCreate(boolean create)
431: throws SocketException {
432: if (isClosed()) {
433: throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$
434: }
435:
436: if (!create || isCreated) {
437: return;
438: }
439:
440: synchronized (this ) {
441: if (isCreated) {
442: return;
443: }
444: try {
445: impl.create(true);
446: } catch (SocketException e) {
447: throw e;
448: } catch (IOException e) {
449: throw new SocketException(e.toString());
450: }
451: isCreated = true;
452: }
453: }
454:
455: /**
456: * Set the SO_REUSEADDR socket option.
457: *
458: * @param reuse
459: * the socket SO_REUSEADDR option setting
460: */
461: public void setReuseAddress(boolean reuse) throws SocketException {
462: checkClosedAndCreate(true);
463: impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE
464: : Boolean.FALSE);
465: }
466:
467: /**
468: * Get the state of the SO_REUSEADDR socket option.
469: */
470: public boolean getReuseAddress() throws SocketException {
471: checkClosedAndCreate(true);
472: return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
473: .booleanValue();
474: }
475:
476: /**
477: * Set the socket receive buffer size.
478: *
479: * @param size
480: * the buffer size, in bytes
481: *
482: * @exception java.net.SocketException
483: * If an error occurs while setting the size or the size is
484: * invalid.
485: */
486: public void setReceiveBufferSize(int size) throws SocketException {
487: checkClosedAndCreate(true);
488: if (size < 1) {
489: throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
490: }
491: impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
492: }
493:
494: /**
495: * Answer the socket receive buffer size (SO_RCVBUF).
496: *
497: * @return int socket receive buffer size
498: */
499: public int getReceiveBufferSize() throws SocketException {
500: checkClosedAndCreate(true);
501: return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF))
502: .intValue();
503: }
504:
505: /**
506: * if ServerSocket is created by a ServerSocketChannel, returns the related
507: * ServerSocketChannel
508: *
509: * @return the related ServerSocketChannel if any
510: */
511: public ServerSocketChannel getChannel() {
512: return null;
513: }
514:
515: /**
516: * sets performance preference for connectionTime,latency and bandwidth
517: *
518: * @param connectionTime
519: * the importance of connect time
520: * @param latency
521: * the importance of latency
522: * @param bandwidth
523: * the importance of bandwidth
524: */
525: public void setPerformancePreferences(int connectionTime,
526: int latency, int bandwidth) {
527: // Our socket implementation only provide one protocol: TCP/IP, so
528: // we do nothing for this method
529: }
530: }
|