1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.local;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.AbstractChannel;
20 import io.netty.channel.Channel;
21 import io.netty.channel.ChannelConfig;
22 import io.netty.channel.ChannelMetadata;
23 import io.netty.channel.ChannelOutboundBuffer;
24 import io.netty.channel.ChannelPipeline;
25 import io.netty.channel.ChannelPromise;
26 import io.netty.channel.DefaultChannelConfig;
27 import io.netty.channel.EventLoop;
28 import io.netty.channel.IoEvent;
29 import io.netty.channel.IoEventLoop;
30 import io.netty.channel.IoRegistration;
31 import io.netty.channel.PreferHeapByteBufAllocator;
32 import io.netty.channel.RecvByteBufAllocator;
33 import io.netty.channel.SingleThreadEventLoop;
34 import io.netty.util.ReferenceCountUtil;
35 import io.netty.util.concurrent.Future;
36 import io.netty.util.concurrent.SingleThreadEventExecutor;
37 import io.netty.util.internal.InternalThreadLocalMap;
38 import io.netty.util.internal.PlatformDependent;
39 import io.netty.util.internal.logging.InternalLogger;
40 import io.netty.util.internal.logging.InternalLoggerFactory;
41
42 import java.net.ConnectException;
43 import java.net.SocketAddress;
44 import java.nio.channels.AlreadyConnectedException;
45 import java.nio.channels.ClosedChannelException;
46 import java.nio.channels.ConnectionPendingException;
47 import java.nio.channels.NotYetConnectedException;
48 import java.util.Queue;
49 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
50
51
52
53
54 public class LocalChannel extends AbstractChannel {
55 private static final InternalLogger logger = InternalLoggerFactory.getInstance(LocalChannel.class);
56 @SuppressWarnings({ "rawtypes" })
57 private static final AtomicReferenceFieldUpdater<LocalChannel, Future> FINISH_READ_FUTURE_UPDATER =
58 AtomicReferenceFieldUpdater.newUpdater(LocalChannel.class, Future.class, "finishReadFuture");
59 private static final AtomicReferenceFieldUpdater<LocalChannel, State> STATE_UPDATER =
60 AtomicReferenceFieldUpdater.newUpdater(LocalChannel.class, State.class, "state");
61 private static final ChannelMetadata METADATA = new ChannelMetadata(false);
62 private static final int MAX_READER_STACK_DEPTH = 8;
63
64 private enum State { OPEN, BOUND, CONNECTED, CLOSED }
65
66 private final ChannelConfig config = new DefaultChannelConfig(this);
67
68 final Queue<Object> inboundBuffer = PlatformDependent.newSpscQueue();
69 private final Runnable readTask = new Runnable() {
70 @Override
71 public void run() {
72
73 if (!inboundBuffer.isEmpty()) {
74 readInbound();
75 }
76 }
77 };
78
79 private final Runnable finishReadTask = new Runnable() {
80 @Override
81 public void run() {
82 finishPeerRead0(LocalChannel.this);
83 }
84 };
85
86 private IoRegistration registration;
87
88 private volatile State state;
89 private volatile LocalChannel peer;
90 private volatile LocalAddress localAddress;
91 private volatile LocalAddress remoteAddress;
92 private volatile ChannelPromise connectPromise;
93 private volatile boolean readInProgress;
94 private volatile boolean writeInProgress;
95 private volatile Future<?> finishReadFuture;
96
97 public LocalChannel() {
98 super(null);
99 config().setAllocator(new PreferHeapByteBufAllocator(config.getAllocator()));
100 }
101
102 protected LocalChannel(LocalServerChannel parent, LocalChannel peer) {
103 super(parent);
104 config().setAllocator(new PreferHeapByteBufAllocator(config.getAllocator()));
105 this.peer = peer;
106 localAddress = parent.localAddress();
107 remoteAddress = peer.localAddress();
108 }
109
110 @Override
111 public ChannelMetadata metadata() {
112 return METADATA;
113 }
114
115 @Override
116 public ChannelConfig config() {
117 return config;
118 }
119
120 @Override
121 public LocalServerChannel parent() {
122 return (LocalServerChannel) super.parent();
123 }
124
125 @Override
126 public LocalAddress localAddress() {
127 return (LocalAddress) super.localAddress();
128 }
129
130 @Override
131 public LocalAddress remoteAddress() {
132 return (LocalAddress) super.remoteAddress();
133 }
134
135 @Override
136 public boolean isOpen() {
137 return state != State.CLOSED;
138 }
139
140 @Override
141 public boolean isActive() {
142 return state == State.CONNECTED;
143 }
144
145 @Override
146 protected AbstractUnsafe newUnsafe() {
147 return new LocalUnsafe();
148 }
149
150 @Override
151 protected boolean isCompatible(EventLoop loop) {
152 return loop instanceof SingleThreadEventLoop ||
153 (loop instanceof IoEventLoop && ((IoEventLoop) loop).isCompatible(LocalUnsafe.class));
154 }
155
156 @Override
157 protected SocketAddress localAddress0() {
158 return localAddress;
159 }
160
161 @Override
162 protected SocketAddress remoteAddress0() {
163 return remoteAddress;
164 }
165
166 @Override
167 protected void doRegister(ChannelPromise promise) {
168 EventLoop loop = eventLoop();
169 if (loop instanceof IoEventLoop) {
170 assert registration == null;
171 ((IoEventLoop) loop).register((LocalUnsafe) unsafe()).addListener(f -> {
172 if (f.isSuccess()) {
173 registration = (IoRegistration) f.getNow();
174 promise.setSuccess();
175 } else {
176 promise.setFailure(f.cause());
177 }
178 });
179 } else {
180 try {
181 ((LocalUnsafe) unsafe()).registered();
182 } catch (Throwable cause) {
183 promise.setFailure(cause);
184 }
185 promise.setSuccess();
186 }
187 }
188
189 @Override
190 protected void doDeregister() throws Exception {
191 EventLoop loop = eventLoop();
192 if (loop instanceof IoEventLoop) {
193 IoRegistration registration = this.registration;
194 if (registration != null) {
195 this.registration = null;
196 registration.cancel();
197 }
198 } else {
199 ((LocalUnsafe) unsafe()).unregistered();
200 }
201 }
202
203 @Override
204 protected void doBind(SocketAddress localAddress) throws Exception {
205 this.localAddress =
206 LocalChannelRegistry.register(this, this.localAddress,
207 localAddress);
208 state = State.BOUND;
209 }
210
211 @Override
212 protected void doDisconnect() throws Exception {
213 doClose();
214 }
215
216 @Override
217 protected void doClose() throws Exception {
218 final LocalChannel peer = this.peer;
219 State oldState = state;
220 State closedFrom = oldState;
221 try {
222 if (oldState != State.CLOSED) {
223
224 if (localAddress != null) {
225 if (parent() == null) {
226 LocalChannelRegistry.unregister(localAddress);
227 }
228 localAddress = null;
229 }
230
231
232
233
234
235 closedFrom = STATE_UPDATER.getAndSet(this, State.CLOSED);
236
237
238 if (writeInProgress && peer != null) {
239 finishPeerRead(peer);
240 }
241
242 ChannelPromise promise = connectPromise;
243 if (promise != null) {
244
245 promise.tryFailure(new ClosedChannelException());
246 connectPromise = null;
247 }
248 }
249
250 if (peer != null && parent() == null && closedFrom != State.CONNECTED) {
251
252
253
254
255 this.peer = null;
256 } else if (peer != null) {
257 this.peer = null;
258
259
260
261 EventLoop peerEventLoop = peer.eventLoop();
262 final boolean peerIsActive = peer.isActive();
263 try {
264 peerEventLoop.execute(new Runnable() {
265 @Override
266 public void run() {
267 peer.tryClose(peerIsActive);
268 }
269 });
270 } catch (Throwable cause) {
271 logger.warn("Releasing Inbound Queues for channels {}-{} because exception occurred!",
272 this, peer, cause);
273 if (peerEventLoop.inEventLoop()) {
274 peer.releaseInboundBuffers();
275 } else {
276
277
278 peer.close();
279 }
280 PlatformDependent.throwException(cause);
281 }
282 }
283 } finally {
284
285 if (oldState != null && oldState != State.CLOSED) {
286
287
288
289
290 releaseInboundBuffers();
291 }
292 }
293 }
294
295 private void tryClose(boolean isActive) {
296 if (isActive) {
297 unsafe().close(unsafe().voidPromise());
298 } else if (connectPromise != null) {
299
300
301
302 ChannelPromise promise = connectPromise;
303 connectPromise = null;
304 peer = null;
305 promise.tryFailure(new ConnectException("connection refused: the accepted channel was closed"));
306 unsafe().close(unsafe().voidPromise());
307 } else {
308 releaseInboundBuffers();
309 }
310 }
311
312 private void readInbound() {
313 RecvByteBufAllocator.Handle handle = unsafe().recvBufAllocHandle();
314 handle.reset(config());
315 ChannelPipeline pipeline = pipeline();
316 do {
317 Object received = inboundBuffer.poll();
318 if (received == null) {
319 break;
320 }
321 if (received instanceof ByteBuf && inboundBuffer.peek() instanceof ByteBuf) {
322 ByteBuf msg = (ByteBuf) received;
323 ByteBuf output = handle.allocate(alloc());
324 if (msg.readableBytes() < output.writableBytes()) {
325
326 output.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
327 msg.release();
328 while ((received = inboundBuffer.peek()) instanceof ByteBuf &&
329 ((ByteBuf) received).readableBytes() < output.writableBytes()) {
330 inboundBuffer.poll();
331 msg = (ByteBuf) received;
332 output.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
333 msg.release();
334 }
335 handle.lastBytesRead(output.readableBytes());
336 received = output;
337 } else {
338
339 handle.lastBytesRead(output.capacity());
340 output.release();
341 }
342 }
343 handle.incMessagesRead(1);
344 pipeline.fireChannelRead(received);
345 } while (handle.continueReading());
346 handle.readComplete();
347 pipeline.fireChannelReadComplete();
348 }
349
350 @Override
351 protected void doBeginRead() throws Exception {
352 if (readInProgress) {
353 return;
354 }
355
356 Queue<Object> inboundBuffer = this.inboundBuffer;
357 if (inboundBuffer.isEmpty()) {
358 readInProgress = true;
359 return;
360 }
361
362 final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
363 final int stackDepth = threadLocals.localChannelReaderStackDepth();
364 if (stackDepth < MAX_READER_STACK_DEPTH) {
365 threadLocals.setLocalChannelReaderStackDepth(stackDepth + 1);
366 try {
367 readInbound();
368 } finally {
369 threadLocals.setLocalChannelReaderStackDepth(stackDepth);
370 }
371 } else {
372 try {
373 eventLoop().execute(readTask);
374 } catch (Throwable cause) {
375 logger.warn("Closing Local channels {}-{} because exception occurred!", this, peer, cause);
376 close();
377 peer.close();
378 PlatformDependent.throwException(cause);
379 }
380 }
381 }
382
383 @Override
384 protected void doWrite(ChannelOutboundBuffer in) throws Exception {
385 switch (state) {
386 case OPEN:
387 case BOUND:
388 throw new NotYetConnectedException();
389 case CLOSED:
390 throw new ClosedChannelException();
391 case CONNECTED:
392 break;
393 }
394
395 final LocalChannel peer = this.peer;
396
397 writeInProgress = true;
398 try {
399 ClosedChannelException exception = null;
400 for (;;) {
401 Object msg = in.current();
402 if (msg == null) {
403 break;
404 }
405 try {
406
407
408 if (peer.state == State.CONNECTED) {
409 peer.inboundBuffer.add(ReferenceCountUtil.retain(msg));
410 in.remove();
411 } else {
412 if (exception == null) {
413 exception = new ClosedChannelException();
414 }
415 in.remove(exception);
416 }
417 } catch (Throwable cause) {
418 in.remove(cause);
419 }
420 }
421 } finally {
422
423
424
425
426
427 writeInProgress = false;
428 }
429
430 finishPeerRead(peer);
431 }
432
433 private void finishPeerRead(final LocalChannel peer) {
434
435 if (peer.eventLoop() == eventLoop() && !peer.writeInProgress) {
436 finishPeerRead0(peer);
437 } else {
438 runFinishPeerReadTask(peer);
439 }
440 }
441
442 private void runFinishTask0() {
443
444
445 if (writeInProgress) {
446 finishReadFuture = eventLoop().submit(finishReadTask);
447 } else {
448 eventLoop().execute(finishReadTask);
449 }
450 }
451
452 private void runFinishPeerReadTask(final LocalChannel peer) {
453 try {
454 peer.runFinishTask0();
455 } catch (Throwable cause) {
456 logger.warn("Closing Local channels {}-{} because exception occurred!", this, peer, cause);
457 close();
458 peer.close();
459 PlatformDependent.throwException(cause);
460 }
461 }
462
463 private void releaseInboundBuffers() {
464 assert eventLoop() == null || eventLoop().inEventLoop();
465 readInProgress = false;
466 Queue<Object> inboundBuffer = this.inboundBuffer;
467 Object msg;
468 while ((msg = inboundBuffer.poll()) != null) {
469 ReferenceCountUtil.release(msg);
470 }
471 }
472
473 private void finishPeerRead0(LocalChannel peer) {
474 Future<?> peerFinishReadFuture = peer.finishReadFuture;
475 if (peerFinishReadFuture != null) {
476 if (!peerFinishReadFuture.isDone()) {
477 runFinishPeerReadTask(peer);
478 return;
479 } else {
480
481 FINISH_READ_FUTURE_UPDATER.compareAndSet(peer, peerFinishReadFuture, null);
482 }
483 }
484
485
486 if (peer.readInProgress && !peer.inboundBuffer.isEmpty()) {
487 peer.readInProgress = false;
488 peer.readInbound();
489 }
490 }
491
492 private class LocalUnsafe extends AbstractUnsafe implements LocalIoHandle {
493
494 private final Runnable shutdownHook = this::closeNow;
495
496 @Override
497 public void close() {
498 close(voidPromise());
499 }
500
501 @Override
502 public void handle(IoRegistration registration, IoEvent event) {
503
504 }
505
506 @Override
507 public void registered() {
508
509
510
511
512
513
514
515
516 final LocalChannel peer = LocalChannel.this.peer;
517 if (peer != null && parent() != null) {
518
519 State oldState = state;
520 state = State.CONNECTED;
521
522
523
524
525 if (STATE_UPDATER.compareAndSet(peer, State.BOUND, State.CONNECTED) ||
526 peer.state == State.CONNECTED) {
527 peer.remoteAddress = parent().localAddress();
528
529
530
531
532
533 peer.eventLoop().execute(new Runnable() {
534 @Override
535 public void run() {
536 ChannelPromise promise = peer.connectPromise;
537
538
539
540 if (promise != null && promise.trySuccess()) {
541 peer.pipeline().fireChannelActive();
542 }
543 }
544 });
545 } else {
546
547
548 LocalChannel.this.peer = null;
549 state = oldState;
550 eventLoop().execute(this::closeNow);
551 }
552 }
553 EventLoop loop = eventLoop();
554 if (!(loop instanceof IoEventLoop) && loop instanceof SingleThreadEventExecutor) {
555 ((SingleThreadEventExecutor) eventLoop()).addShutdownHook(shutdownHook);
556 }
557 }
558
559 @Override
560 public void unregistered() {
561 EventLoop loop = eventLoop();
562 if (!(loop instanceof IoEventLoop) && loop instanceof SingleThreadEventExecutor) {
563 ((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook);
564 }
565 }
566
567 @Override
568 public void closeNow() {
569 close(voidPromise());
570 }
571
572 @Override
573 public void connect(final SocketAddress remoteAddress,
574 SocketAddress localAddress, final ChannelPromise promise) {
575 if (!promise.setUncancellable() || !ensureOpen(promise)) {
576 return;
577 }
578
579 if (state == State.CONNECTED) {
580 Exception cause = new AlreadyConnectedException();
581 safeSetFailure(promise, cause);
582 return;
583 }
584
585 if (connectPromise != null) {
586 throw new ConnectionPendingException();
587 }
588
589 connectPromise = promise;
590
591 if (state != State.BOUND) {
592
593 if (localAddress == null) {
594 localAddress = new LocalAddress(LocalChannel.this);
595 }
596 }
597
598 if (localAddress != null) {
599 try {
600 doBind(localAddress);
601 } catch (Throwable t) {
602 safeSetFailure(promise, t);
603 close(voidPromise());
604 return;
605 }
606 }
607
608 Channel boundChannel = LocalChannelRegistry.get(remoteAddress);
609 if (!(boundChannel instanceof LocalServerChannel)) {
610 Exception cause = new ConnectException("connection refused: " + remoteAddress);
611 safeSetFailure(promise, cause);
612 close(voidPromise());
613 return;
614 }
615
616 LocalServerChannel serverChannel = (LocalServerChannel) boundChannel;
617 peer = serverChannel.serve(LocalChannel.this);
618 }
619 }
620 }