30 import java.net.InetSocketAddress; |
30 import java.net.InetSocketAddress; |
31 import java.net.ServerSocket; |
31 import java.net.ServerSocket; |
32 import java.net.Socket; |
32 import java.net.Socket; |
33 import java.net.SocketAddress; |
33 import java.net.SocketAddress; |
34 import java.net.SocketException; |
34 import java.net.SocketException; |
35 import java.net.SocketTimeoutException; |
35 import java.net.SocketOption; |
36 import java.net.StandardSocketOptions; |
36 import java.net.StandardSocketOptions; |
37 import java.nio.channels.IllegalBlockingModeException; |
37 import java.nio.channels.IllegalBlockingModeException; |
38 import java.nio.channels.NotYetBoundException; |
|
39 import java.nio.channels.ServerSocketChannel; |
38 import java.nio.channels.ServerSocketChannel; |
40 import java.nio.channels.SocketChannel; |
39 import java.nio.channels.SocketChannel; |
|
40 import java.util.Set; |
|
41 |
|
42 import static java.util.concurrent.TimeUnit.MILLISECONDS; |
41 |
43 |
42 |
44 |
43 // Make a server-socket channel look like a server socket. |
45 // Make a server-socket channel look like a server socket. |
44 // |
46 // |
45 // The methods in this class are defined in exactly the same order as in |
47 // The methods in this class are defined in exactly the same order as in |
54 private final ServerSocketChannelImpl ssc; |
56 private final ServerSocketChannelImpl ssc; |
55 |
57 |
56 // Timeout "option" value for accepts |
58 // Timeout "option" value for accepts |
57 private volatile int timeout; |
59 private volatile int timeout; |
58 |
60 |
59 public static ServerSocket create(ServerSocketChannelImpl ssc) { |
61 static ServerSocket create(ServerSocketChannelImpl ssc) { |
60 try { |
62 return new ServerSocketAdaptor(ssc); |
61 return new ServerSocketAdaptor(ssc); |
63 } |
62 } catch (IOException x) { |
64 |
63 throw new Error(x); |
65 private ServerSocketAdaptor(ServerSocketChannelImpl ssc) { |
64 } |
66 super(DummySocketImpl.create()); |
65 } |
|
66 |
|
67 // ## super will create a useless impl |
|
68 private ServerSocketAdaptor(ServerSocketChannelImpl ssc) throws IOException { |
|
69 this.ssc = ssc; |
67 this.ssc = ssc; |
70 } |
68 } |
71 |
69 |
|
70 @Override |
72 public void bind(SocketAddress local) throws IOException { |
71 public void bind(SocketAddress local) throws IOException { |
73 bind(local, 50); |
72 bind(local, 50); |
74 } |
73 } |
75 |
74 |
|
75 @Override |
76 public void bind(SocketAddress local, int backlog) throws IOException { |
76 public void bind(SocketAddress local, int backlog) throws IOException { |
77 if (local == null) |
77 if (local == null) |
78 local = new InetSocketAddress(0); |
78 local = new InetSocketAddress(0); |
79 try { |
79 try { |
80 ssc.bind(local, backlog); |
80 ssc.bind(local, backlog); |
81 } catch (Exception x) { |
81 } catch (Exception x) { |
82 Net.translateException(x); |
82 Net.translateException(x); |
83 } |
83 } |
84 } |
84 } |
85 |
85 |
|
86 @Override |
86 public InetAddress getInetAddress() { |
87 public InetAddress getInetAddress() { |
87 InetSocketAddress local = ssc.localAddress(); |
88 InetSocketAddress local = ssc.localAddress(); |
88 if (local == null) { |
89 if (local == null) { |
89 return null; |
90 return null; |
90 } else { |
91 } else { |
91 return Net.getRevealedLocalAddress(local).getAddress(); |
92 return Net.getRevealedLocalAddress(local).getAddress(); |
92 } |
93 } |
93 } |
94 } |
94 |
95 |
|
96 @Override |
95 public int getLocalPort() { |
97 public int getLocalPort() { |
96 InetSocketAddress local = ssc.localAddress(); |
98 InetSocketAddress local = ssc.localAddress(); |
97 if (local == null) { |
99 if (local == null) { |
98 return -1; |
100 return -1; |
99 } else { |
101 } else { |
100 return local.getPort(); |
102 return local.getPort(); |
101 } |
103 } |
102 } |
104 } |
103 |
105 |
|
106 @Override |
104 public Socket accept() throws IOException { |
107 public Socket accept() throws IOException { |
105 synchronized (ssc.blockingLock()) { |
108 SocketChannel sc = null; |
106 try { |
109 try { |
107 if (!ssc.isBound()) |
110 int timeout = this.timeout; |
108 throw new NotYetBoundException(); |
111 if (timeout > 0) { |
109 |
112 long nanos = MILLISECONDS.toNanos(timeout); |
110 long to = this.timeout; |
113 sc = ssc.blockingAccept(nanos); |
111 if (to == 0) { |
114 } else { |
112 // for compatibility reasons: accept connection if available |
115 // accept connection if possible when non-blocking (to preserve |
113 // when configured non-blocking |
116 // long standing behavior) |
114 SocketChannel sc = ssc.accept(); |
117 sc = ssc.accept(); |
115 if (sc == null && !ssc.isBlocking()) |
118 if (sc == null) { |
116 throw new IllegalBlockingModeException(); |
119 throw new IllegalBlockingModeException(); |
117 return sc.socket(); |
|
118 } |
120 } |
119 |
|
120 if (!ssc.isBlocking()) |
|
121 throw new IllegalBlockingModeException(); |
|
122 for (;;) { |
|
123 long st = System.currentTimeMillis(); |
|
124 if (ssc.pollAccept(to)) |
|
125 return ssc.accept().socket(); |
|
126 to -= System.currentTimeMillis() - st; |
|
127 if (to <= 0) |
|
128 throw new SocketTimeoutException(); |
|
129 } |
|
130 |
|
131 } catch (Exception x) { |
|
132 Net.translateException(x); |
|
133 assert false; |
|
134 return null; // Never happens |
|
135 } |
121 } |
136 } |
122 } catch (Exception e) { |
137 } |
123 Net.translateException(e); |
138 |
124 } |
|
125 return sc.socket(); |
|
126 } |
|
127 |
|
128 @Override |
139 public void close() throws IOException { |
129 public void close() throws IOException { |
140 ssc.close(); |
130 ssc.close(); |
141 } |
131 } |
142 |
132 |
|
133 @Override |
143 public ServerSocketChannel getChannel() { |
134 public ServerSocketChannel getChannel() { |
144 return ssc; |
135 return ssc; |
145 } |
136 } |
146 |
137 |
|
138 @Override |
147 public boolean isBound() { |
139 public boolean isBound() { |
148 return ssc.isBound(); |
140 return ssc.isBound(); |
149 } |
141 } |
150 |
142 |
|
143 @Override |
151 public boolean isClosed() { |
144 public boolean isClosed() { |
152 return !ssc.isOpen(); |
145 return !ssc.isOpen(); |
153 } |
146 } |
154 |
147 |
|
148 @Override |
155 public void setSoTimeout(int timeout) throws SocketException { |
149 public void setSoTimeout(int timeout) throws SocketException { |
|
150 if (!ssc.isOpen()) |
|
151 throw new SocketException("Socket is closed"); |
|
152 if (timeout < 0) |
|
153 throw new IllegalArgumentException("timeout < 0"); |
156 this.timeout = timeout; |
154 this.timeout = timeout; |
157 } |
155 } |
158 |
156 |
|
157 @Override |
159 public int getSoTimeout() throws SocketException { |
158 public int getSoTimeout() throws SocketException { |
|
159 if (!ssc.isOpen()) |
|
160 throw new SocketException("Socket is closed"); |
160 return timeout; |
161 return timeout; |
161 } |
162 } |
162 |
163 |
|
164 @Override |
163 public void setReuseAddress(boolean on) throws SocketException { |
165 public void setReuseAddress(boolean on) throws SocketException { |
164 try { |
166 try { |
165 ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on); |
167 ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on); |
166 } catch (IOException x) { |
168 } catch (IOException x) { |
167 Net.translateToSocketException(x); |
169 Net.translateToSocketException(x); |
168 } |
170 } |
169 } |
171 } |
170 |
172 |
|
173 @Override |
171 public boolean getReuseAddress() throws SocketException { |
174 public boolean getReuseAddress() throws SocketException { |
172 try { |
175 try { |
173 return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue(); |
176 return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue(); |
174 } catch (IOException x) { |
177 } catch (IOException x) { |
175 Net.translateToSocketException(x); |
178 Net.translateToSocketException(x); |
176 return false; // Never happens |
179 return false; // Never happens |
177 } |
180 } |
178 } |
181 } |
179 |
182 |
|
183 @Override |
180 public String toString() { |
184 public String toString() { |
181 if (!isBound()) |
185 if (!isBound()) |
182 return "ServerSocket[unbound]"; |
186 return "ServerSocket[unbound]"; |
183 return "ServerSocket[addr=" + getInetAddress() + |
187 return "ServerSocket[addr=" + getInetAddress() + |
184 ",localport=" + getLocalPort() + "]"; |
188 ",localport=" + getLocalPort() + "]"; |
185 } |
189 } |
186 |
190 |
|
191 @Override |
187 public void setReceiveBufferSize(int size) throws SocketException { |
192 public void setReceiveBufferSize(int size) throws SocketException { |
188 // size 0 valid for ServerSocketChannel, invalid for ServerSocket |
193 // size 0 valid for ServerSocketChannel, invalid for ServerSocket |
189 if (size <= 0) |
194 if (size <= 0) |
190 throw new IllegalArgumentException("size cannot be 0 or negative"); |
195 throw new IllegalArgumentException("size cannot be 0 or negative"); |
191 try { |
196 try { |