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