View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.socket.oio;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.channel.Channel;
20  import io.netty.channel.ChannelException;
21  import io.netty.channel.ChannelFuture;
22  import io.netty.channel.ChannelFutureListener;
23  import io.netty.channel.ChannelPromise;
24  import io.netty.channel.ConnectTimeoutException;
25  import io.netty.channel.EventLoop;
26  import io.netty.channel.oio.OioByteStreamChannel;
27  import io.netty.channel.socket.ServerSocketChannel;
28  import io.netty.channel.socket.SocketChannel;
29  import io.netty.util.internal.SocketUtils;
30  import io.netty.util.internal.UnstableApi;
31  import io.netty.util.internal.logging.InternalLogger;
32  import io.netty.util.internal.logging.InternalLoggerFactory;
33  
34  import java.io.IOException;
35  import java.net.InetSocketAddress;
36  import java.net.Socket;
37  import java.net.SocketAddress;
38  import java.net.SocketTimeoutException;
39  
40  /**
41   * A {@link SocketChannel} which is using Old-Blocking-IO
42   *
43   * @deprecated use NIO / EPOLL / KQUEUE transport.
44   */
45  @Deprecated
46  public class OioSocketChannel extends OioByteStreamChannel implements SocketChannel {
47  
48      private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioSocketChannel.class);
49  
50      private final Socket socket;
51      private final OioSocketChannelConfig config;
52  
53      /**
54       * Create a new instance with an new {@link Socket}
55       */
56      public OioSocketChannel() {
57          this(new Socket());
58      }
59  
60      /**
61       * Create a new instance from the given {@link Socket}
62       *
63       * @param socket    the {@link Socket} which is used by this instance
64       */
65      public OioSocketChannel(Socket socket) {
66          this(null, socket);
67      }
68  
69      /**
70       * Create a new instance from the given {@link Socket}
71       *
72       * @param parent    the parent {@link Channel} which was used to create this instance. This can be null if the
73       *                  {@link} has no parent as it was created by your self.
74       * @param socket    the {@link Socket} which is used by this instance
75       */
76      public OioSocketChannel(Channel parent, Socket socket) {
77          super(parent);
78          this.socket = socket;
79          config = new DefaultOioSocketChannelConfig(this, socket);
80  
81          boolean success = false;
82          try {
83              if (socket.isConnected()) {
84                  activate(socket.getInputStream(), socket.getOutputStream());
85              }
86              socket.setSoTimeout(SO_TIMEOUT);
87              success = true;
88          } catch (Exception e) {
89              throw new ChannelException("failed to initialize a socket", e);
90          } finally {
91              if (!success) {
92                  try {
93                      socket.close();
94                  } catch (IOException e) {
95                      logger.warn("Failed to close a socket.", e);
96                  }
97              }
98          }
99      }
100 
101     @Override
102     public ServerSocketChannel parent() {
103         return (ServerSocketChannel) super.parent();
104     }
105 
106     @Override
107     public OioSocketChannelConfig config() {
108         return config;
109     }
110 
111     @Override
112     public boolean isOpen() {
113         return !socket.isClosed();
114     }
115 
116     @Override
117     public boolean isActive() {
118         return !socket.isClosed() && socket.isConnected();
119     }
120 
121     @Override
122     public boolean isOutputShutdown() {
123         return socket.isOutputShutdown() || !isActive();
124     }
125 
126     @Override
127     public boolean isInputShutdown() {
128         return socket.isInputShutdown() || !isActive();
129     }
130 
131     @Override
132     public boolean isShutdown() {
133         return socket.isInputShutdown() && socket.isOutputShutdown() || !isActive();
134     }
135 
136     @UnstableApi
137     @Override
138     protected final void doShutdownOutput() throws Exception {
139         shutdownOutput0();
140     }
141 
142     @Override
143     public ChannelFuture shutdownOutput() {
144         return shutdownOutput(newPromise());
145     }
146 
147     @Override
148     public ChannelFuture shutdownInput() {
149         return shutdownInput(newPromise());
150     }
151 
152     @Override
153     public ChannelFuture shutdown() {
154         return shutdown(newPromise());
155     }
156 
157     @Override
158     protected int doReadBytes(ByteBuf buf) throws Exception {
159         if (socket.isClosed()) {
160             return -1;
161         }
162         try {
163             return super.doReadBytes(buf);
164         } catch (SocketTimeoutException ignored) {
165             return 0;
166         }
167     }
168 
169     @Override
170     public ChannelFuture shutdownOutput(final ChannelPromise promise) {
171         EventLoop loop = eventLoop();
172         if (loop.inEventLoop()) {
173             shutdownOutput0(promise);
174         } else {
175             loop.execute(new Runnable() {
176                 @Override
177                 public void run() {
178                     shutdownOutput0(promise);
179                 }
180             });
181         }
182         return promise;
183     }
184 
185     private void shutdownOutput0(ChannelPromise promise) {
186         try {
187             shutdownOutput0();
188             promise.setSuccess();
189         } catch (Throwable t) {
190             promise.setFailure(t);
191         }
192     }
193 
194     private void shutdownOutput0() throws IOException {
195         socket.shutdownOutput();
196     }
197 
198     @Override
199     public ChannelFuture shutdownInput(final ChannelPromise promise) {
200         EventLoop loop = eventLoop();
201         if (loop.inEventLoop()) {
202             shutdownInput0(promise);
203         } else {
204             loop.execute(new Runnable() {
205                 @Override
206                 public void run() {
207                     shutdownInput0(promise);
208                 }
209             });
210         }
211         return promise;
212     }
213 
214     private void shutdownInput0(ChannelPromise promise) {
215         try {
216             socket.shutdownInput();
217             promise.setSuccess();
218         } catch (Throwable t) {
219             promise.setFailure(t);
220         }
221     }
222 
223     @Override
224     public ChannelFuture shutdown(final ChannelPromise promise) {
225         ChannelFuture shutdownOutputFuture = shutdownOutput();
226         if (shutdownOutputFuture.isDone()) {
227             shutdownOutputDone(shutdownOutputFuture, promise);
228         } else {
229             shutdownOutputFuture.addListener(new ChannelFutureListener() {
230                 @Override
231                 public void operationComplete(final ChannelFuture shutdownOutputFuture) throws Exception {
232                     shutdownOutputDone(shutdownOutputFuture, promise);
233                 }
234             });
235         }
236         return promise;
237     }
238 
239     private void shutdownOutputDone(final ChannelFuture shutdownOutputFuture, final ChannelPromise promise) {
240         ChannelFuture shutdownInputFuture = shutdownInput();
241         if (shutdownInputFuture.isDone()) {
242             shutdownDone(shutdownOutputFuture, shutdownInputFuture, promise);
243         } else {
244             shutdownInputFuture.addListener(new ChannelFutureListener() {
245                 @Override
246                 public void operationComplete(ChannelFuture shutdownInputFuture) throws Exception {
247                     shutdownDone(shutdownOutputFuture, shutdownInputFuture, promise);
248                 }
249             });
250         }
251     }
252 
253     private static void shutdownDone(ChannelFuture shutdownOutputFuture,
254                                      ChannelFuture shutdownInputFuture,
255                                      ChannelPromise promise) {
256         Throwable shutdownOutputCause = shutdownOutputFuture.cause();
257         Throwable shutdownInputCause = shutdownInputFuture.cause();
258         if (shutdownOutputCause != null) {
259             if (shutdownInputCause != null) {
260                 logger.debug("Exception suppressed because a previous exception occurred.",
261                         shutdownInputCause);
262             }
263             promise.setFailure(shutdownOutputCause);
264         } else if (shutdownInputCause != null) {
265             promise.setFailure(shutdownInputCause);
266         } else {
267             promise.setSuccess();
268         }
269     }
270 
271     @Override
272     public InetSocketAddress localAddress() {
273         return (InetSocketAddress) super.localAddress();
274     }
275 
276     @Override
277     public InetSocketAddress remoteAddress() {
278         return (InetSocketAddress) super.remoteAddress();
279     }
280 
281     @Override
282     protected SocketAddress localAddress0() {
283         return socket.getLocalSocketAddress();
284     }
285 
286     @Override
287     protected SocketAddress remoteAddress0() {
288         return socket.getRemoteSocketAddress();
289     }
290 
291     @Override
292     protected void doBind(SocketAddress localAddress) throws Exception {
293         SocketUtils.bind(socket, localAddress);
294     }
295 
296     @Override
297     protected void doConnect(SocketAddress remoteAddress,
298             SocketAddress localAddress) throws Exception {
299         if (localAddress != null) {
300             SocketUtils.bind(socket, localAddress);
301         }
302 
303         final int connectTimeoutMillis = config().getConnectTimeoutMillis();
304         boolean success = false;
305         try {
306             SocketUtils.connect(socket, remoteAddress, connectTimeoutMillis);
307             activate(socket.getInputStream(), socket.getOutputStream());
308             success = true;
309         } catch (SocketTimeoutException e) {
310             ConnectTimeoutException cause = new ConnectTimeoutException("connection timed out after " +
311                     connectTimeoutMillis + " ms: " + remoteAddress);
312             cause.setStackTrace(e.getStackTrace());
313             throw cause;
314         } finally {
315             if (!success) {
316                 doClose();
317             }
318         }
319     }
320 
321     @Override
322     protected void doDisconnect() throws Exception {
323         doClose();
324     }
325 
326     @Override
327     protected void doClose() throws Exception {
328         socket.close();
329     }
330 
331     protected boolean checkInputShutdown() {
332         if (isInputShutdown()) {
333             try {
334                 Thread.sleep(config().getSoTimeout());
335             } catch (Throwable e) {
336                 // ignore
337             }
338             return true;
339         }
340         return false;
341     }
342 
343     @Deprecated
344     @Override
345     protected void setReadPending(boolean readPending) {
346         super.setReadPending(readPending);
347     }
348 
349     final void clearReadPending0() {
350         clearReadPending();
351     }
352 }