1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.nio;
21
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.Socket;
25 import java.nio.ByteBuffer;
26 import java.nio.channels.SelectionKey;
27 import java.nio.channels.SocketChannel;
28
29 import org.apache.mina.api.IoService;
30 import org.apache.mina.service.idlechecker.IdleChecker;
31 import org.apache.mina.session.WriteRequest;
32 import org.apache.mina.transport.ConnectFuture;
33 import org.apache.mina.transport.tcp.ProxyTcpSessionConfig;
34 import org.apache.mina.transport.tcp.TcpSessionConfig;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43
44
45 public class NioTcpSession extends AbstractNioSession implements SelectorListener {
46
47 private static final Logger LOG = LoggerFactory.getLogger(NioTcpSession.class);
48
49
50 private final SelectorLoop selectorLoop;
51
52
53 private final TcpSessionConfig configuration;
54
55
56 private ConnectFuture connectFuture;
57
58
59 private SelectionKey selectionKey;
60
61
62 private ByteBuffer sendBuffer;
63
64
65 private int sendBufferSize;
66
67
68 final SelectorLoop selectorLoop, final IdleChecker idleChecker) {
69 super(service, channel, idleChecker);
70 this.selectorLoop = selectorLoop;
71 this.configuration = new ProxyTcpSessionConfig(channel.socket());
72 sendBufferSize = configuration.getSendBufferSize();
73 sendBuffer = ByteBuffer.allocateDirect(sendBufferSize);
74 }
75
76 void setConnectFuture(ConnectFuture connectFuture) {
77 this.connectFuture = connectFuture;
78 }
79
80
81
82
83
84
85 SocketChannel getSocketChannel() {
86 return (SocketChannel) channel;
87 }
88
89
90
91
92 @Override
93 public InetSocketAddress getRemoteAddress() {
94 if (channel == null) {
95 return null;
96 }
97 final Socket socket = ((SocketChannel) channel).socket();
98
99 if (socket == null) {
100 return null;
101 }
102
103 return (InetSocketAddress) socket.getRemoteSocketAddress();
104 }
105
106
107
108
109 @Override
110 public InetSocketAddress getLocalAddress() {
111 if (channel == null) {
112 return null;
113 }
114
115 final Socket socket = ((SocketChannel) channel).socket();
116
117 if (socket == null) {
118 return null;
119 }
120
121 return (InetSocketAddress) socket.getLocalSocketAddress();
122 }
123
124
125
126
127 @Override
128 public void suspendRead() {
129
130 throw new RuntimeException("Not implemented");
131 }
132
133
134
135
136 @Override
137 public void suspendWrite() {
138
139 throw new RuntimeException("Not implemented");
140 }
141
142
143
144
145 @Override
146 protected int writeDirect(Object message) {
147 try {
148
149 if (!isRegisteredForWrite()) {
150
151 return ((SocketChannel) channel).write((ByteBuffer) message);
152 } else {
153 return -1;
154 }
155 } catch (final IOException e) {
156 LOG.error("Exception while reading : ", e);
157 processException(e);
158
159 return -1;
160 }
161 }
162
163
164
165
166 @Override
167 protected ByteBuffer convertToDirectBuffer(WriteRequest writeRequest, boolean createNew) {
168 ByteBuffer message = (ByteBuffer) writeRequest.getMessage();
169
170 if (!message.isDirect()) {
171 int remaining = message.remaining();
172
173 if ((remaining > sendBufferSize) || createNew) {
174 ByteBuffer directBuffer = ByteBuffer.allocateDirect(remaining);
175 directBuffer.put(message);
176 directBuffer.flip();
177 writeRequest.setMessage(directBuffer);
178
179 return directBuffer;
180 } else {
181 sendBuffer.clear();
182 sendBuffer.put(message);
183 sendBuffer.flip();
184 writeRequest.setMessage(sendBuffer);
185
186 return sendBuffer;
187 }
188 }
189
190 return message;
191 }
192
193
194
195
196 @Override
197 public void resumeRead() {
198
199 throw new RuntimeException("Not implemented");
200 }
201
202
203
204
205 @Override
206 public void resumeWrite() {
207
208 throw new RuntimeException("Not implemented");
209 }
210
211
212
213
214 @Override
215 public boolean isReadSuspended() {
216
217 return false;
218 }
219
220
221
222
223 @Override
224 public boolean isWriteSuspended() {
225
226 throw new RuntimeException("Not implemented");
227 }
228
229
230
231
232 @Override
233 public TcpSessionConfig getConfig() {
234 return configuration;
235 }
236
237
238
239
240 void setConnected() {
241 if (!isCreated()) {
242 throw new RuntimeException("Trying to open a non created session");
243 }
244
245 state = SessionState.CONNECTED;
246
247 if (connectFuture != null) {
248 connectFuture.complete(this);
249
250 connectFuture = null;
251 }
252
253 processSessionOpen();
254 }
255
256
257
258
259 @Override
260 protected void channelClose() {
261 try {
262 selectorLoop.unregister(this, channel);
263 channel.close();
264 } catch (final IOException e) {
265 LOG.error("Exception while closing the channel : ", e);
266 processException(e);
267 }
268 }
269
270
271
272
273 @Override
274 public void flushWriteQueue() {
275
276 selectorLoop.modifyRegistration(false, !isReadSuspended(), true, this, channel, true);
277 }
278
279
280
281
282
283
284 private void processRead(final ByteBuffer readBuffer) {
285 try {
286 LOG.debug("readable session : {}", this);
287
288
289 final int readCount = ((SocketChannel) channel).read(readBuffer);
290
291 LOG.debug("read {} bytes", readCount);
292
293 if (readCount < 0) {
294
295 LOG.debug("session closed by the remote peer");
296 close(true);
297 } else if (readCount > 0) {
298
299
300
301 readBuffer.flip();
302
303 if (isSecured()) {
304
305
306 final SslHelper sslHelper = getAttribute(SSL_HELPER, null);
307
308 if (sslHelper == null) {
309 throw new IllegalStateException();
310 }
311
312 sslHelper.processRead(this, readBuffer);
313
314
315 } else {
316
317 processMessageReceived(readBuffer);
318
319
320 readBuffer.clear();
321 }
322
323
324 idleChecker.sessionRead(this, System.currentTimeMillis());
325 }
326 } catch (final IOException e) {
327 LOG.error("Exception while reading : ", e);
328 processException(e);
329 }
330 }
331
332
333
334
335 @Override
336 public void ready(final boolean accept, boolean connect, final boolean read, final ByteBuffer readBuffer,
337 final boolean write) {
338 if (LOG.isDebugEnabled()) {
339 LOG.debug("session {} ready for accept={}, connect={}, read={}, write={}", new Object[] { this, accept,
340 connect, read, write });
341 }
342 if (connect) {
343 try {
344
345 boolean isConnected = ((SocketChannel) channel).finishConnect();
346
347 if (!isConnected) {
348 LOG.error("unable to connect session {}", this);
349 } else {
350
351 selectionKey.cancel();
352 selectionKey = null;
353
354
355 selectorLoop.register(false, false, true, false, this, channel, new RegistrationCallback() {
356
357 @Override
358 public void done(SelectionKey selectionKey) {
359 setConnected();
360 }
361 });
362 }
363 } catch (IOException e) {
364 LOG.debug("Connection error, we cancel the future", e);
365 if (connectFuture != null) {
366 connectFuture.error(e);
367 }
368 }
369 }
370
371 if (read) {
372 processRead(readBuffer);
373 }
374
375 if (write) {
376 processWrite(selectorLoop);
377 }
378 if (accept) {
379 throw new IllegalStateException("accept event should never occur on NioTcpSession");
380 }
381 }
382
383 void setSelectionKey(SelectionKey key) {
384 this.selectionKey = key;
385 }
386 }