31 import java.net.*; |
31 import java.net.*; |
32 import java.nio.channels.*; |
32 import java.nio.channels.*; |
33 import java.nio.channels.spi.*; |
33 import java.nio.channels.spi.*; |
34 import java.security.AccessController; |
34 import java.security.AccessController; |
35 import java.security.PrivilegedAction; |
35 import java.security.PrivilegedAction; |
36 import java.util.HashSet; |
36 import java.util.*; |
37 import java.util.Iterator; |
|
38 |
37 |
39 |
38 |
40 /** |
39 /** |
41 * An implementation of ServerSocketChannels |
40 * An implementation of ServerSocketChannels |
42 */ |
41 */ |
73 private static final int ST_INUSE = 0; |
72 private static final int ST_INUSE = 0; |
74 private static final int ST_KILLED = 1; |
73 private static final int ST_KILLED = 1; |
75 private int state = ST_UNINITIALIZED; |
74 private int state = ST_UNINITIALIZED; |
76 |
75 |
77 // Binding |
76 // Binding |
78 private SocketAddress localAddress = null; // null => unbound |
77 private SocketAddress localAddress; // null => unbound |
79 |
|
80 // Options, created on demand |
|
81 private SocketOpts.IP.TCP options = null; |
|
82 |
78 |
83 // Our socket adaptor, if any |
79 // Our socket adaptor, if any |
84 ServerSocket socket; |
80 ServerSocket socket; |
85 |
81 |
86 // -- End of fields protected by stateLock |
82 // -- End of fields protected by stateLock |
101 this.fdVal = IOUtil.fdVal(fd); |
97 this.fdVal = IOUtil.fdVal(fd); |
102 this.state = ST_INUSE; |
98 this.state = ST_INUSE; |
103 localAddress = Net.localAddress(fd); |
99 localAddress = Net.localAddress(fd); |
104 } |
100 } |
105 |
101 |
106 |
|
107 public ServerSocket socket() { |
102 public ServerSocket socket() { |
108 synchronized (stateLock) { |
103 synchronized (stateLock) { |
109 if (socket == null) |
104 if (socket == null) |
110 socket = ServerSocketAdaptor.create(this); |
105 socket = ServerSocketAdaptor.create(this); |
111 return socket; |
106 return socket; |
112 } |
107 } |
113 } |
108 } |
114 |
109 |
|
110 @Override |
|
111 public SocketAddress getLocalAddress() throws IOException { |
|
112 synchronized (stateLock) { |
|
113 if (!isOpen()) |
|
114 return null; |
|
115 return localAddress; |
|
116 } |
|
117 } |
|
118 |
|
119 @Override |
|
120 public ServerSocketChannel setOption(SocketOption name, Object value) |
|
121 throws IOException |
|
122 { |
|
123 if (name == null) |
|
124 throw new NullPointerException(); |
|
125 if (!options().contains(name)) |
|
126 throw new IllegalArgumentException("invalid option name"); |
|
127 |
|
128 synchronized (stateLock) { |
|
129 if (!isOpen()) |
|
130 throw new ClosedChannelException(); |
|
131 |
|
132 // no options that require special handling |
|
133 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
|
134 return this; |
|
135 } |
|
136 } |
|
137 |
|
138 @Override |
|
139 @SuppressWarnings("unchecked") |
|
140 public <T> T getOption(SocketOption<T> name) |
|
141 throws IOException |
|
142 { |
|
143 if (name == null) |
|
144 throw new NullPointerException(); |
|
145 if (!options().contains(name)) |
|
146 throw new IllegalArgumentException("invalid option name"); |
|
147 |
|
148 synchronized (stateLock) { |
|
149 if (!isOpen()) |
|
150 throw new ClosedChannelException(); |
|
151 |
|
152 // no options that require special handling |
|
153 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
|
154 } |
|
155 } |
|
156 |
|
157 private static class LazyInitialization { |
|
158 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
|
159 |
|
160 private static Set<SocketOption<?>> defaultOptions() { |
|
161 HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2); |
|
162 set.add(StandardSocketOption.SO_RCVBUF); |
|
163 set.add(StandardSocketOption.SO_REUSEADDR); |
|
164 return Collections.unmodifiableSet(set); |
|
165 } |
|
166 } |
|
167 |
|
168 @Override |
|
169 public final Set<SocketOption<?>> options() { |
|
170 return LazyInitialization.defaultOptions; |
|
171 } |
|
172 |
115 public boolean isBound() { |
173 public boolean isBound() { |
116 synchronized (stateLock) { |
174 synchronized (stateLock) { |
117 return localAddress != null; |
175 return localAddress != null; |
118 } |
176 } |
119 } |
177 } |
122 synchronized (stateLock) { |
180 synchronized (stateLock) { |
123 return localAddress; |
181 return localAddress; |
124 } |
182 } |
125 } |
183 } |
126 |
184 |
127 public void bind(SocketAddress local, int backlog) throws IOException { |
185 @Override |
|
186 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
128 synchronized (lock) { |
187 synchronized (lock) { |
129 if (!isOpen()) |
188 if (!isOpen()) |
130 throw new ClosedChannelException(); |
189 throw new ClosedChannelException(); |
131 if (isBound()) |
190 if (isBound()) |
132 throw new AlreadyBoundException(); |
191 throw new AlreadyBoundException(); |
133 InetSocketAddress isa = Net.checkAddress(local); |
192 InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : |
|
193 Net.checkAddress(local); |
134 SecurityManager sm = System.getSecurityManager(); |
194 SecurityManager sm = System.getSecurityManager(); |
135 if (sm != null) |
195 if (sm != null) |
136 sm.checkListen(isa.getPort()); |
196 sm.checkListen(isa.getPort()); |
137 Net.bind(fd, isa.getAddress(), isa.getPort()); |
197 Net.bind(fd, isa.getAddress(), isa.getPort()); |
138 listen(fd, backlog < 1 ? 50 : backlog); |
198 Net.listen(fd, backlog < 1 ? 50 : backlog); |
139 synchronized (stateLock) { |
199 synchronized (stateLock) { |
140 localAddress = Net.localAddress(fd); |
200 localAddress = Net.localAddress(fd); |
141 } |
201 } |
142 } |
202 } |
|
203 return this; |
143 } |
204 } |
144 |
205 |
145 public SocketChannel accept() throws IOException { |
206 public SocketChannel accept() throws IOException { |
146 synchronized (lock) { |
207 synchronized (lock) { |
147 if (!isOpen()) |
208 if (!isOpen()) |
194 |
255 |
195 protected void implConfigureBlocking(boolean block) throws IOException { |
256 protected void implConfigureBlocking(boolean block) throws IOException { |
196 IOUtil.configureBlocking(fd, block); |
257 IOUtil.configureBlocking(fd, block); |
197 } |
258 } |
198 |
259 |
199 public SocketOpts options() { |
|
200 synchronized (stateLock) { |
|
201 if (options == null) { |
|
202 SocketOptsImpl.Dispatcher d |
|
203 = new SocketOptsImpl.Dispatcher() { |
|
204 int getInt(int opt) throws IOException { |
|
205 return Net.getIntOption(fd, opt); |
|
206 } |
|
207 void setInt(int opt, int arg) throws IOException { |
|
208 Net.setIntOption(fd, opt, arg); |
|
209 } |
|
210 }; |
|
211 options = new SocketOptsImpl.IP.TCP(d); |
|
212 } |
|
213 return options; |
|
214 } |
|
215 } |
|
216 |
|
217 protected void implCloseSelectableChannel() throws IOException { |
260 protected void implCloseSelectableChannel() throws IOException { |
218 synchronized (stateLock) { |
261 synchronized (stateLock) { |
219 nd.preClose(fd); |
262 nd.preClose(fd); |
220 long th = thread; |
263 long th = thread; |
221 if (th != 0) |
264 if (th != 0) |
318 return sb.toString(); |
361 return sb.toString(); |
319 } |
362 } |
320 |
363 |
321 // -- Native methods -- |
364 // -- Native methods -- |
322 |
365 |
323 private static native void listen(FileDescriptor fd, int backlog) |
|
324 throws IOException; |
|
325 |
|
326 // Accepts a new connection, setting the given file descriptor to refer to |
366 // Accepts a new connection, setting the given file descriptor to refer to |
327 // the new socket and setting isaa[0] to the socket's remote address. |
367 // the new socket and setting isaa[0] to the socket's remote address. |
328 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no |
368 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no |
329 // connections are pending) or IOStatus.INTERRUPTED. |
369 // connections are pending) or IOStatus.INTERRUPTED. |
330 // |
370 // |