1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
53
54 public OioSocketChannel() {
55 this(new Socket());
56 }
57
58
59
60
61
62
63 public OioSocketChannel(Socket socket) {
64 this(null, socket);
65 }
66
67
68
69
70
71
72
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
246 }
247 return true;
248 }
249 return false;
250 }
251
252 @Override
253 protected void setReadPending(boolean readPending) {
254 super.setReadPending(readPending);
255 }
256 }