1 /*
2 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package sun.nio.ch;
27
28 import java.io;
29 import java.lang.ref;
30 import java.net;
31 import java.nio;
32 import java.nio.channels;
33 import java.security.AccessController;
34 import java.security.PrivilegedExceptionAction;
35 import java.util;
36
37
38 // Make a socket channel look like a socket.
39 //
40 // The only aspects of java.net.Socket-hood that we don't attempt to emulate
41 // here are the interrupted-I/O exceptions (which our Solaris implementations
42 // attempt to support) and the sending of urgent data. Otherwise an adapted
43 // socket should look enough like a real java.net.Socket to fool most of the
44 // developers most of the time, right down to the exception message strings.
45 //
46 // The methods in this class are defined in exactly the same order as in
47 // java.net.Socket so as to simplify tracking future changes to that class.
48 //
49
50 public class SocketAdaptor
51 extends Socket
52 {
53
54 // The channel being adapted
55 private final SocketChannelImpl sc;
56
57 // Option adaptor object, created on demand
58 private volatile OptionAdaptor opts = null;
59
60 // Timeout "option" value for reads
61 private volatile int timeout = 0;
62
63 // Traffic-class/Type-of-service
64 private volatile int trafficClass = 0;
65
66
67 // ## super will create a useless impl
68 private SocketAdaptor(SocketChannelImpl sc) {
69 this.sc = sc;
70 }
71
72 public static Socket create(SocketChannelImpl sc) {
73 return new SocketAdaptor(sc);
74 }
75
76 public SocketChannel getChannel() {
77 return sc;
78 }
79
80 // Override this method just to protect against changes in the superclass
81 //
82 public void connect(SocketAddress remote) throws IOException {
83 connect(remote, 0);
84 }
85
86 public void connect(SocketAddress remote, int timeout) throws IOException {
87 if (remote == null)
88 throw new IllegalArgumentException("connect: The address can't be null");
89 if (timeout < 0)
90 throw new IllegalArgumentException("connect: timeout can't be negative");
91
92 synchronized (sc.blockingLock()) {
93 if (!sc.isBlocking())
94 throw new IllegalBlockingModeException();
95
96 try {
97
98 if (timeout == 0) {
99 sc.connect(remote);
100 return;
101 }
102
103 // Implement timeout with a selector
104 SelectionKey sk = null;
105 Selector sel = null;
106 sc.configureBlocking(false);
107 try {
108 if (sc.connect(remote))
109 return;
110 sel = Util.getTemporarySelector(sc);
111 sk = sc.register(sel, SelectionKey.OP_CONNECT);
112 long to = timeout;
113 for (;;) {
114 if (!sc.isOpen())
115 throw new ClosedChannelException();
116 long st = System.currentTimeMillis();
117 int ns = sel.select(to);
118 if (ns > 0 &&
119 sk.isConnectable() && sc.finishConnect())
120 break;
121 sel.selectedKeys().remove(sk);
122 to -= System.currentTimeMillis() - st;
123 if (to <= 0) {
124 try {
125 sc.close();
126 } catch (IOException x) { }
127 throw new SocketTimeoutException();
128 }
129 }
130 } finally {
131 if (sk != null)
132 sk.cancel();
133 if (sc.isOpen())
134 sc.configureBlocking(true);
135 if (sel != null)
136 Util.releaseTemporarySelector(sel);
137 }
138
139 } catch (Exception x) {
140 Net.translateException(x, true);
141 }
142 }
143
144 }
145
146 public void bind(SocketAddress local) throws IOException {
147 try {
148 if (local == null)
149 local = new InetSocketAddress(0);
150 sc.bind(local);
151 } catch (Exception x) {
152 Net.translateException(x);
153 }
154 }
155
156 public InetAddress getInetAddress() {
157 if (!sc.isConnected())
158 return null;
159 return Net.asInetSocketAddress(sc.remoteAddress()).getAddress();
160 }
161
162 public InetAddress getLocalAddress() {
163 if (!sc.isBound())
164 return new InetSocketAddress(0).getAddress();
165 return Net.asInetSocketAddress(sc.localAddress()).getAddress();
166 }
167
168 public int getPort() {
169 if (!sc.isConnected())
170 return 0;
171 return Net.asInetSocketAddress(sc.remoteAddress()).getPort();
172 }
173
174 public int getLocalPort() {
175 if (!sc.isBound())
176 return -1;
177 return Net.asInetSocketAddress(sc.localAddress()).getPort();
178 }
179
180 private class SocketInputStream
181 extends ChannelInputStream
182 {
183 private SocketInputStream() {
184 super(sc);
185 }
186
187 protected int read(ByteBuffer bb)
188 throws IOException
189 {
190 synchronized (sc.blockingLock()) {
191 if (!sc.isBlocking())
192 throw new IllegalBlockingModeException();
193 if (timeout == 0)
194 return sc.read(bb);
195
196 // Implement timeout with a selector
197 SelectionKey sk = null;
198 Selector sel = null;
199 sc.configureBlocking(false);
200 try {
201 int n;
202 if ((n = sc.read(bb)) != 0)
203 return n;
204 sel = Util.getTemporarySelector(sc);
205 sk = sc.register(sel, SelectionKey.OP_READ);
206 long to = timeout;
207 for (;;) {
208 if (!sc.isOpen())
209 throw new ClosedChannelException();
210 long st = System.currentTimeMillis();
211 int ns = sel.select(to);
212 if (ns > 0 && sk.isReadable()) {
213 if ((n = sc.read(bb)) != 0)
214 return n;
215 }
216 sel.selectedKeys().remove(sk);
217 to -= System.currentTimeMillis() - st;
218 if (to <= 0)
219 throw new SocketTimeoutException();
220 }
221 } finally {
222 if (sk != null)
223 sk.cancel();
224 if (sc.isOpen())
225 sc.configureBlocking(true);
226 if (sel != null)
227 Util.releaseTemporarySelector(sel);
228 }
229
230 }
231 }
232 }
233
234 private InputStream socketInputStream = null;
235
236 public InputStream getInputStream() throws IOException {
237 if (!sc.isOpen())
238 throw new SocketException("Socket is closed");
239 if (!sc.isConnected())
240 throw new SocketException("Socket is not connected");
241 if (!sc.isInputOpen())
242 throw new SocketException("Socket input is shutdown");
243 if (socketInputStream == null) {
244 try {
245 socketInputStream = AccessController.doPrivileged(
246 new PrivilegedExceptionAction<InputStream>() {
247 public InputStream run() throws IOException {
248 return new SocketInputStream();
249 }
250 });
251 } catch (java.security.PrivilegedActionException e) {
252 throw (IOException)e.getException();
253 }
254 }
255 return socketInputStream;
256 }
257
258 public OutputStream getOutputStream() throws IOException {
259 if (!sc.isOpen())
260 throw new SocketException("Socket is closed");
261 if (!sc.isConnected())
262 throw new SocketException("Socket is not connected");
263 if (!sc.isOutputOpen())
264 throw new SocketException("Socket output is shutdown");
265 OutputStream os = null;
266 try {
267 os = AccessController.doPrivileged(
268 new PrivilegedExceptionAction<OutputStream>() {
269 public OutputStream run() throws IOException {
270 return Channels.newOutputStream(sc);
271 }
272 });
273 } catch (java.security.PrivilegedActionException e) {
274 throw (IOException)e.getException();
275 }
276 return os;
277 }
278
279 private OptionAdaptor opts() {
280 if (opts == null)
281 opts = new OptionAdaptor(sc);
282 return opts;
283 }
284
285 public void setTcpNoDelay(boolean on) throws SocketException {
286 opts().setTcpNoDelay(on);
287 }
288
289 public boolean getTcpNoDelay() throws SocketException {
290 return opts().getTcpNoDelay();
291 }
292
293 public void setSoLinger(boolean on, int linger) throws SocketException {
294 opts().setSoLinger(on, linger);
295 }
296
297 public int getSoLinger() throws SocketException {
298 return opts().getSoLinger();
299 }
300
301 public void sendUrgentData(int data) throws IOException {
302 throw new SocketException("Urgent data not supported");
303 }
304
305 public void setOOBInline(boolean on) throws SocketException {
306 opts().setOOBInline(on);
307 }
308
309 public boolean getOOBInline() throws SocketException {
310 return opts().getOOBInline();
311 }
312
313 public void setSoTimeout(int timeout) throws SocketException {
314 if (timeout < 0)
315 throw new IllegalArgumentException("timeout can't be negative");
316 this.timeout = timeout;
317 }
318
319 public int getSoTimeout() throws SocketException {
320 return timeout;
321 }
322
323 public void setSendBufferSize(int size) throws SocketException {
324 opts().setSendBufferSize(size);
325 }
326
327 public int getSendBufferSize() throws SocketException {
328 return opts().getSendBufferSize();
329 }
330
331 public void setReceiveBufferSize(int size) throws SocketException {
332 opts().setReceiveBufferSize(size);
333 }
334
335 public int getReceiveBufferSize() throws SocketException {
336 return opts().getReceiveBufferSize();
337 }
338
339 public void setKeepAlive(boolean on) throws SocketException {
340 opts().setKeepAlive(on);
341 }
342
343 public boolean getKeepAlive() throws SocketException {
344 return opts().getKeepAlive();
345 }
346
347 public void setTrafficClass(int tc) throws SocketException {
348 opts().setTrafficClass(tc);
349 trafficClass = tc;
350 }
351
352 public int getTrafficClass() throws SocketException {
353 int tc = opts().getTrafficClass();
354 if (tc < 0) {
355 tc = trafficClass;
356 }
357 return tc;
358 }
359
360 public void setReuseAddress(boolean on) throws SocketException {
361 opts().setReuseAddress(on);
362 }
363
364 public boolean getReuseAddress() throws SocketException {
365 return opts().getReuseAddress();
366 }
367
368 public void close() throws IOException {
369 try {
370 sc.close();
371 } catch (Exception x) {
372 Net.translateToSocketException(x);
373 }
374 }
375
376 public void shutdownInput() throws IOException {
377 try {
378 sc.shutdownInput();
379 } catch (Exception x) {
380 Net.translateException(x);
381 }
382 }
383
384 public void shutdownOutput() throws IOException {
385 try {
386 sc.shutdownOutput();
387 } catch (Exception x) {
388 Net.translateException(x);
389 }
390 }
391
392 public String toString() {
393 if (sc.isConnected())
394 return "Socket[addr=" + getInetAddress() +
395 ",port=" + getPort() +
396 ",localport=" + getLocalPort() + "]";
397 return "Socket[unconnected]";
398 }
399
400 public boolean isConnected() {
401 return sc.isConnected();
402 }
403
404 public boolean isBound() {
405 return sc.isBound();
406 }
407
408 public boolean isClosed() {
409 return !sc.isOpen();
410 }
411
412 public boolean isInputShutdown() {
413 return !sc.isInputOpen();
414 }
415
416 public boolean isOutputShutdown() {
417 return !sc.isOutputOpen();
418 }
419
420 }