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    *   http://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.ChannelPromise;
23  import io.netty.channel.ConnectTimeoutException;
24  import io.netty.channel.EventLoop;
25  import io.netty.channel.oio.OioByteStreamChannel;
26  import io.netty.channel.socket.ServerSocketChannel;
27  import io.netty.channel.socket.SocketChannel;
28  import io.netty.util.internal.SocketUtils;
29  import io.netty.util.internal.UnstableApi;
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  public class OioSocketChannel extends OioByteStreamChannel
43                                implements SocketChannel {
44  
45      private static final InternalLogger logger =
46              InternalLoggerFactory.getInstance(OioSocketChannel.class);
47  
48      private final Socket socket;
49      private final OioSocketChannelConfig config;
50  
51      /**
52       * Create a new instance with an new {@link Socket}
53       */
54      public OioSocketChannel() {
55          this(new Socket());
56      }
57  
58      /**
59       * Create a new instance from the given {@link Socket}
60       *
61       * @param socket    the {@link Socket} which is used by this instance
62       */
63      public OioSocketChannel(Socket socket) {
64          this(null, socket);
65      }
66  
67      /**
68       * Create a new instance from the given {@link Socket}
69       *
70       * @param parent    the parent {@link Channel} which was used to create this instance. This can be null if the
71       *                  {@link} has no parent as it was created by your self.
72       * @param socket    the {@link Socket} which is used by this instance
73       */
74      public OioSocketChannel(Channel parent, Socket socket) {
75          super(parent);
76          this.socket = socket;
77          config = new DefaultOioSocketChannelConfig(this, socket);
78  
79          boolean success = false;
80          try {
81              if (socket.isConnected()) {
82                  activate(socket.getInputStream(), socket.getOutputStream());
83              }
84              socket.setSoTimeout(SO_TIMEOUT);
85              success = true;
86          } catch (Exception e) {
87              throw new ChannelException("failed to initialize a socket", e);
88          } finally {
89              if (!success) {
90                  try {
91                      socket.close();
92                  } catch (IOException e) {
93                      logger.warn("Failed to close a socket.", e);
94                  }
95              }
96          }
97      }
98  
99      @Override
100     public ServerSocketChannel parent() {
101         return (ServerSocketChannel) super.parent();
102     }
103 
104     @Override
105     public OioSocketChannelConfig config() {
106         return config;
107     }
108 
109     @Override
110     public boolean isOpen() {
111         return !socket.isClosed();
112     }
113 
114     @Override
115     public boolean isActive() {
116         return !socket.isClosed() && socket.isConnected();
117     }
118 
119     @Override
120     public boolean isInputShutdown() {
121         return super.isInputShutdown();
122     }
123 
124     @Override
125     public boolean isOutputShutdown() {
126         return socket.isOutputShutdown() || !isActive();
127     }
128 
129     @UnstableApi
130     @Override
131     protected final void doShutdownOutput() throws Exception {
132         shutdownOutput0();
133     }
134 
135     @Override
136     public ChannelFuture shutdownOutput() {
137         return shutdownOutput(newPromise());
138     }
139 
140     @Override
141     protected int doReadBytes(ByteBuf buf) throws Exception {
142         if (socket.isClosed()) {
143             return -1;
144         }
145         try {
146             return super.doReadBytes(buf);
147         } catch (SocketTimeoutException ignored) {
148             return 0;
149         }
150     }
151 
152     @Override
153     public ChannelFuture shutdownOutput(final ChannelPromise promise) {
154         EventLoop loop = eventLoop();
155         if (loop.inEventLoop()) {
156             shutdownOutput0(promise);
157         } else {
158             loop.execute(new Runnable() {
159                 @Override
160                 public void run() {
161                     shutdownOutput0(promise);
162                 }
163             });
164         }
165         return promise;
166     }
167 
168     private void shutdownOutput0(ChannelPromise promise) {
169         try {
170             shutdownOutput0();
171             promise.setSuccess();
172         } catch (Throwable t) {
173             promise.setFailure(t);
174         }
175     }
176 
177     private void shutdownOutput0() throws IOException {
178         socket.shutdownOutput();
179     }
180 
181     @Override
182     public InetSocketAddress localAddress() {
183         return (InetSocketAddress) super.localAddress();
184     }
185 
186     @Override
187     public InetSocketAddress remoteAddress() {
188         return (InetSocketAddress) super.remoteAddress();
189     }
190 
191     @Override
192     protected SocketAddress localAddress0() {
193         return socket.getLocalSocketAddress();
194     }
195 
196     @Override
197     protected SocketAddress remoteAddress0() {
198         return socket.getRemoteSocketAddress();
199     }
200 
201     @Override
202     protected void doBind(SocketAddress localAddress) throws Exception {
203         SocketUtils.bind(socket, localAddress);
204     }
205 
206     @Override
207     protected void doConnect(SocketAddress remoteAddress,
208             SocketAddress localAddress) throws Exception {
209         if (localAddress != null) {
210             SocketUtils.bind(socket, localAddress);
211         }
212 
213         boolean success = false;
214         try {
215             SocketUtils.connect(socket, remoteAddress, config().getConnectTimeoutMillis());
216             activate(socket.getInputStream(), socket.getOutputStream());
217             success = true;
218         } catch (SocketTimeoutException e) {
219             ConnectTimeoutException cause = new ConnectTimeoutException("connection timed out: " + remoteAddress);
220             cause.setStackTrace(e.getStackTrace());
221             throw cause;
222         } finally {
223             if (!success) {
224                 doClose();
225             }
226         }
227     }
228 
229     @Override
230     protected void doDisconnect() throws Exception {
231         doClose();
232     }
233 
234     @Override
235     protected void doClose() throws Exception {
236         socket.close();
237     }
238 
239     @Override
240     protected boolean checkInputShutdown() {
241         if (isInputShutdown()) {
242             try {
243                 Thread.sleep(config().getSoTimeout());
244             } catch (Throwable e) {
245                 // ignore
246             }
247             return true;
248         }
249         return false;
250     }
251 
252     @Override
253     protected void setReadPending(boolean readPending) {
254         super.setReadPending(readPending);
255     }
256 }