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