1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.tomcat.util.net;
18
19 import java.io.IOException;
20 import java.nio.ByteBuffer;
21 import java.nio.channels.ByteChannel;
22 import java.nio.channels.GatheringByteChannel;
23 import java.nio.channels.ScatteringByteChannel;
24 import java.nio.channels.Selector;
25 import java.nio.channels.SocketChannel;
26
27 import org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper;
28 import org.apache.tomcat.util.res.StringManager;
29
30 /**
31  * Base class for a SocketChannel wrapper used by the endpoint.
32  * This way, logic for an SSL socket channel remains the same as for
33  * a non SSL, making sure we don't need to code for any exception cases.
34  *
35  * @version 1.0
36  */

37 public class NioChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel {
38
39     protected static final StringManager sm = StringManager.getManager(NioChannel.class);
40
41     protected static final ByteBuffer emptyBuf = ByteBuffer.allocate(0);
42
43     protected final SocketBufferHandler bufHandler;
44     protected SocketChannel sc = null;
45     protected NioSocketWrapper socketWrapper = null;
46
47     public NioChannel(SocketBufferHandler bufHandler) {
48         this.bufHandler = bufHandler;
49     }
50
51     /**
52      * Reset the channel
53      *
54      * @param channel the socket channel
55      * @param socketWrapper the socket wrapper
56      * @throws IOException If a problem was encountered resetting the channel
57      */

58     public void reset(SocketChannel channel, NioSocketWrapper socketWrapper) throws IOException {
59         this.sc = channel;
60         this.socketWrapper = socketWrapper;
61         bufHandler.reset();
62     }
63
64     /**
65      * @return the socketWrapper
66      */

67     NioSocketWrapper getSocketWrapper() {
68         return socketWrapper;
69     }
70
71     /**
72      * Free the channel memory
73      */

74     public void free() {
75         bufHandler.free();
76     }
77
78     /**
79      * Returns true if the network buffer has been flushed out and is empty.
80      *
81      * @param block     Unused. May be used when overridden
82      * @param s         Unused. May be used when overridden
83      * @param timeout   Unused. May be used when overridden
84      * @return Always returns <code>true</code> since there is no network buffer
85      *         in the regular channel
86      *
87      * @throws IOException Never for non-secure channel
88      */

89     public boolean flush(boolean block, Selector s, long timeout)
90             throws IOException {
91         return true;
92     }
93
94
95     /**
96      * Closes this channel.
97      *
98      * @throws IOException If an I/O error occurs
99      */

100     @Override
101     public void close() throws IOException {
102         sc.close();
103     }
104
105     /**
106      * Close the connection.
107      *
108      * @param force Should the underlying socket be forcibly closed?
109      *
110      * @throws IOException If closing the secure channel fails.
111      */

112     public void close(boolean force) throws IOException {
113         if (isOpen() || force) {
114             close();
115         }
116     }
117
118     /**
119      * Tells whether or not this channel is open.
120      *
121      * @return <code>true</code> if, and only ifthis channel is open
122      */

123     @Override
124     public boolean isOpen() {
125         return sc.isOpen();
126     }
127
128     /**
129      * Writes a sequence of bytes to this channel from the given buffer.
130      *
131      * @param src The buffer from which bytes are to be retrieved
132      * @return The number of bytes written, possibly zero
133      * @throws IOException If some other I/O error occurs
134      */

135     @Override
136     public int write(ByteBuffer src) throws IOException {
137         checkInterruptStatus();
138         return sc.write(src);
139     }
140
141     @Override
142     public long write(ByteBuffer[] srcs) throws IOException {
143         return write(srcs, 0, srcs.length);
144     }
145
146     @Override
147     public long write(ByteBuffer[] srcs, int offset, int length)
148             throws IOException {
149         checkInterruptStatus();
150         return sc.write(srcs, offset, length);
151     }
152
153     /**
154      * Reads a sequence of bytes from this channel into the given buffer.
155      *
156      * @param dst The buffer into which bytes are to be transferred
157      * @return The number of bytes read, possibly zero, or <code>-1</code> if
158      *         the channel has reached end-of-stream
159      * @throws IOException If some other I/O error occurs
160      */

161     @Override
162     public int read(ByteBuffer dst) throws IOException {
163         return sc.read(dst);
164     }
165
166     @Override
167     public long read(ByteBuffer[] dsts) throws IOException {
168         return read(dsts, 0, dsts.length);
169     }
170
171     @Override
172     public long read(ByteBuffer[] dsts, int offset, int length)
173             throws IOException {
174         return sc.read(dsts, offset, length);
175     }
176
177     public SocketBufferHandler getBufHandler() {
178         return bufHandler;
179     }
180
181     public SocketChannel getIOChannel() {
182         return sc;
183     }
184
185     public boolean isClosing() {
186         return false;
187     }
188
189     public boolean isHandshakeComplete() {
190         return true;
191     }
192
193     /**
194      * Performs SSL handshake hence is a no-op for the non-secure
195      * implementation.
196      *
197      * @param read  Unused in non-secure implementation
198      * @param write Unused in non-secure implementation
199      * @return Always returns zero
200      * @throws IOException Never for non-secure channel
201      */

202     public int handshake(boolean read, boolean write) throws IOException {
203         return 0;
204     }
205
206     @Override
207     public String toString() {
208         return super.toString() + ":" + sc.toString();
209     }
210
211     public int getOutboundRemaining() {
212         return 0;
213     }
214
215     /**
216      * Return true if the buffer wrote data. NO-OP for non-secure channel.
217      *
218      * @return Always returns {@code falsefor non-secure channel
219      *
220      * @throws IOException Never for non-secure channel
221      */

222     public boolean flushOutbound() throws IOException {
223         return false;
224     }
225
226     /**
227      * This method should be used to check the interrupt status before
228      * attempting a write.
229      *
230      * If a thread has been interrupted and the interrupt has not been cleared
231      * then an attempt to write to the socket will fail. When this happens the
232      * socket is removed from the poller without the socket being selected. This
233      * results in a connection limit leak for NIO as the endpoint expects the
234      * socket to be selected even in error conditions.
235      * @throws IOException If the current thread was interrupted
236      */

237     protected void checkInterruptStatus() throws IOException {
238         if (Thread.interrupted()) {
239             throw new IOException(sm.getString("channel.nio.interrupted"));
240         }
241     }
242
243     private ApplicationBufferHandler appReadBufHandler;
244     public void setAppReadBufHandler(ApplicationBufferHandler handler) {
245         this.appReadBufHandler = handler;
246     }
247     protected ApplicationBufferHandler getAppReadBufHandler() {
248         return appReadBufHandler;
249     }
250
251     static final NioChannel CLOSED_NIO_CHANNEL = new ClosedNioChannel();
252     public static class ClosedNioChannel extends NioChannel {
253         public ClosedNioChannel() {
254             super(SocketBufferHandler.EMPTY);
255         }
256         @Override
257         public void close() throws IOException {
258         }
259         @Override
260         public boolean isOpen() {
261             return false;
262         }
263         @Override
264         public void reset(SocketChannel channel, NioSocketWrapper socketWrapper) throws IOException {
265         }
266         @Override
267         public void free() {
268         }
269         @Override
270         public void setAppReadBufHandler(ApplicationBufferHandler handler) {
271         }
272         @Override
273         public int read(ByteBuffer dst) throws IOException {
274             return -1;
275         }
276         @Override
277         public long read(ByteBuffer[] dsts, int offset, int length)
278                 throws IOException {
279             return -1L;
280         }
281         @Override
282         public int write(ByteBuffer src) throws IOException {
283             checkInterruptStatus();
284             return -1;
285         }
286         @Override
287         public long write(ByteBuffer[] srcs, int offset, int length)
288                 throws IOException {
289             return -1L;
290         }
291         @Override
292         public String toString() {
293             return "Closed NioChannel";
294         }
295     }
296
297 }
298