53 |
53 |
54 /** |
54 /** |
55 * An implementation of ServerSocketChannels |
55 * An implementation of ServerSocketChannels |
56 */ |
56 */ |
57 |
57 |
58 class ServerSocketChannelImpl |
58 public abstract class ServerSocketChannelImpl |
59 extends ServerSocketChannel |
59 extends ServerSocketChannel |
60 implements SelChImpl |
60 implements SelChImpl |
61 { |
61 { |
62 // Used to make native close and configure calls |
62 // Used to make native close and configure calls |
63 private static final NativeDispatcher nd = new SocketDispatcher(); |
63 static final NativeDispatcher nd = new SocketDispatcher(); |
64 |
64 |
65 // Our file descriptor |
65 // Our file descriptor |
66 private final FileDescriptor fd; |
66 final FileDescriptor fd; |
67 private final int fdVal; |
67 final int fdVal; |
68 |
68 |
69 // Lock held by thread currently blocked on this channel |
69 // Lock held by thread currently blocked on this channel |
70 private final ReentrantLock acceptLock = new ReentrantLock(); |
70 final ReentrantLock acceptLock = new ReentrantLock(); |
71 |
71 |
72 // Lock held by any thread that modifies the state fields declared below |
72 // Lock held by any thread that modifies the state fields declared below |
73 // DO NOT invoke a blocking I/O operation while holding this lock! |
73 // DO NOT invoke a blocking I/O operation while holding this lock! |
74 private final Object stateLock = new Object(); |
74 final Object stateLock = new Object(); |
75 |
75 |
76 // -- The following fields are protected by stateLock |
76 // -- The following fields are protected by stateLock |
77 |
77 |
78 // Channel state, increases monotonically |
78 // Channel state, increases monotonically |
79 private static final int ST_INUSE = 0; |
79 static final int ST_INUSE = 0; |
80 private static final int ST_CLOSING = 1; |
80 static final int ST_CLOSING = 1; |
81 private static final int ST_CLOSED = 2; |
81 static final int ST_CLOSED = 2; |
82 private int state; |
82 int state; |
83 |
83 |
84 // ID of native thread currently blocked in this channel, for signalling |
84 // ID of native thread currently blocked in this channel, for signalling |
85 private long thread; |
85 long thread; |
86 |
86 |
87 // Binding |
87 // Binding |
88 private InetSocketAddress localAddress; // null => unbound |
88 SocketAddress localAddress; // null => unbound |
89 |
|
90 // set true when exclusive binding is on and SO_REUSEADDR is emulated |
|
91 private boolean isReuseAddress; |
|
92 |
|
93 // Our socket adaptor, if any |
|
94 private ServerSocket socket; |
|
95 |
89 |
96 // -- End of fields protected by stateLock |
90 // -- End of fields protected by stateLock |
97 |
91 |
98 |
92 ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd) |
99 ServerSocketChannelImpl(SelectorProvider sp) { |
|
100 super(sp); |
|
101 this.fd = Net.serverSocket(true); |
|
102 this.fdVal = IOUtil.fdVal(fd); |
|
103 } |
|
104 |
|
105 ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) |
|
106 throws IOException |
93 throws IOException |
107 { |
94 { |
108 super(sp); |
95 super(sp); |
109 this.fd = fd; |
96 this.fd = fd; |
110 this.fdVal = IOUtil.fdVal(fd); |
97 this.fdVal = IOUtil.fdVal(fd); |
111 if (bound) { |
|
112 synchronized (stateLock) { |
|
113 localAddress = Net.localAddress(fd); |
|
114 } |
|
115 } |
|
116 } |
98 } |
117 |
99 |
118 // @throws ClosedChannelException if channel is closed |
100 // @throws ClosedChannelException if channel is closed |
119 private void ensureOpen() throws ClosedChannelException { |
101 void ensureOpen() throws ClosedChannelException { |
120 if (!isOpen()) |
102 if (!isOpen()) |
121 throw new ClosedChannelException(); |
103 throw new ClosedChannelException(); |
122 } |
104 } |
123 |
105 |
124 @Override |
106 abstract SocketAddress getRevealedLocalAddress(SocketAddress addr); |
125 public ServerSocket socket() { |
107 |
126 synchronized (stateLock) { |
108 abstract String getRevealedLocalAddressAsString(SocketAddress addr); |
127 if (socket == null) |
|
128 socket = ServerSocketAdaptor.create(this); |
|
129 return socket; |
|
130 } |
|
131 } |
|
132 |
109 |
133 @Override |
110 @Override |
134 public SocketAddress getLocalAddress() throws IOException { |
111 public SocketAddress getLocalAddress() throws IOException { |
135 synchronized (stateLock) { |
112 synchronized (stateLock) { |
136 ensureOpen(); |
113 ensureOpen(); |
137 return (localAddress == null) |
114 return (localAddress == null) |
138 ? null |
115 ? null |
139 : Net.getRevealedLocalAddress(localAddress); |
116 : getRevealedLocalAddress(localAddress); |
140 } |
117 } |
141 } |
118 } |
142 |
119 |
143 @Override |
|
144 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) |
|
145 throws IOException |
|
146 { |
|
147 Objects.requireNonNull(name); |
|
148 if (!supportedOptions().contains(name)) |
|
149 throw new UnsupportedOperationException("'" + name + "' not supported"); |
|
150 if (!name.type().isInstance(value)) |
|
151 throw new IllegalArgumentException("Invalid value '" + value + "'"); |
|
152 |
|
153 synchronized (stateLock) { |
|
154 ensureOpen(); |
|
155 |
|
156 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
|
157 // SO_REUSEADDR emulated when using exclusive bind |
|
158 isReuseAddress = (Boolean)value; |
|
159 } else { |
|
160 // no options that require special handling |
|
161 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
|
162 } |
|
163 return this; |
|
164 } |
|
165 } |
|
166 |
|
167 @Override |
|
168 @SuppressWarnings("unchecked") |
|
169 public <T> T getOption(SocketOption<T> name) |
|
170 throws IOException |
|
171 { |
|
172 Objects.requireNonNull(name); |
|
173 if (!supportedOptions().contains(name)) |
|
174 throw new UnsupportedOperationException("'" + name + "' not supported"); |
|
175 |
|
176 synchronized (stateLock) { |
|
177 ensureOpen(); |
|
178 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
|
179 // SO_REUSEADDR emulated when using exclusive bind |
|
180 return (T)Boolean.valueOf(isReuseAddress); |
|
181 } |
|
182 // no options that require special handling |
|
183 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
|
184 } |
|
185 } |
|
186 |
|
187 private static class DefaultOptionsHolder { |
|
188 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
|
189 |
|
190 private static Set<SocketOption<?>> defaultOptions() { |
|
191 HashSet<SocketOption<?>> set = new HashSet<>(); |
|
192 set.add(StandardSocketOptions.SO_RCVBUF); |
|
193 set.add(StandardSocketOptions.SO_REUSEADDR); |
|
194 if (Net.isReusePortAvailable()) { |
|
195 set.add(StandardSocketOptions.SO_REUSEPORT); |
|
196 } |
|
197 set.addAll(ExtendedSocketOptions.serverSocketOptions()); |
|
198 return Collections.unmodifiableSet(set); |
|
199 } |
|
200 } |
|
201 |
|
202 @Override |
|
203 public final Set<SocketOption<?>> supportedOptions() { |
|
204 return DefaultOptionsHolder.defaultOptions; |
|
205 } |
|
206 |
|
207 @Override |
|
208 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
|
209 synchronized (stateLock) { |
|
210 ensureOpen(); |
|
211 if (localAddress != null) |
|
212 throw new AlreadyBoundException(); |
|
213 InetSocketAddress isa = (local == null) |
|
214 ? new InetSocketAddress(0) |
|
215 : Net.checkAddress(local); |
|
216 SecurityManager sm = System.getSecurityManager(); |
|
217 if (sm != null) |
|
218 sm.checkListen(isa.getPort()); |
|
219 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
|
220 Net.bind(fd, isa.getAddress(), isa.getPort()); |
|
221 Net.listen(fd, backlog < 1 ? 50 : backlog); |
|
222 localAddress = Net.localAddress(fd); |
|
223 } |
|
224 return this; |
|
225 } |
|
226 |
120 |
227 /** |
121 /** |
228 * Marks the beginning of an I/O operation that might block. |
122 * Marks the beginning of an I/O operation that might block. |
229 * |
123 * |
230 * @throws ClosedChannelException if the channel is closed |
124 * @throws ClosedChannelException if the channel is closed |
320 begin(true); |
217 begin(true); |
321 // change socket to non-blocking |
218 // change socket to non-blocking |
322 lockedConfigureBlocking(false); |
219 lockedConfigureBlocking(false); |
323 try { |
220 try { |
324 long startNanos = System.nanoTime(); |
221 long startNanos = System.nanoTime(); |
325 n = Net.accept(fd, newfd, isaa); |
222 n = implAccept(fd, newfd, isaa); |
326 while (n == IOStatus.UNAVAILABLE && isOpen()) { |
223 while (n == IOStatus.UNAVAILABLE && isOpen()) { |
327 long remainingNanos = nanos - (System.nanoTime() - startNanos); |
224 long remainingNanos = nanos - (System.nanoTime() - startNanos); |
328 if (remainingNanos <= 0) { |
225 if (remainingNanos <= 0) { |
329 throw new SocketTimeoutException("Accept timed out"); |
226 throw new SocketTimeoutException("Accept timed out"); |
330 } |
227 } |
331 park(Net.POLLIN, remainingNanos); |
228 park(Net.POLLIN, remainingNanos); |
332 n = Net.accept(fd, newfd, isaa); |
229 n = implAccept(fd, newfd, isaa); |
333 } |
230 } |
334 } finally { |
231 } finally { |
335 // restore socket to blocking mode |
232 // restore socket to blocking mode |
336 lockedConfigureBlocking(true); |
233 lockedConfigureBlocking(true); |
337 } |
234 } |