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.channel.AbstractServerChannel;
19 import io.netty.channel.ChannelConfig;
20 import io.netty.channel.ChannelPipeline;
21 import io.netty.channel.DefaultChannelConfig;
22 import io.netty.channel.EventLoop;
23 import io.netty.channel.PreferHeapByteBufAllocator;
24 import io.netty.channel.RecvByteBufAllocator;
25 import io.netty.channel.ServerChannel;
26 import io.netty.channel.ServerChannelRecvByteBufAllocator;
27 import io.netty.channel.SingleThreadEventLoop;
28 import io.netty.util.concurrent.SingleThreadEventExecutor;
29
30 import java.net.SocketAddress;
31 import java.util.ArrayDeque;
32 import java.util.Queue;
33
34
35
36
37 public class LocalServerChannel extends AbstractServerChannel {
38
39 private final ChannelConfig config =
40 new DefaultChannelConfig(this, new ServerChannelRecvByteBufAllocator()) { };
41 private final Queue<Object> inboundBuffer = new ArrayDeque<Object>();
42 private final Runnable shutdownHook = new Runnable() {
43 @Override
44 public void run() {
45 unsafe().close(unsafe().voidPromise());
46 }
47 };
48
49 private volatile int state;
50 private volatile LocalAddress localAddress;
51 private volatile boolean acceptInProgress;
52
53 public LocalServerChannel() {
54 config().setAllocator(new PreferHeapByteBufAllocator(config.getAllocator()));
55 }
56
57 @Override
58 public ChannelConfig config() {
59 return config;
60 }
61
62 @Override
63 public LocalAddress localAddress() {
64 return (LocalAddress) super.localAddress();
65 }
66
67 @Override
68 public LocalAddress remoteAddress() {
69 return (LocalAddress) super.remoteAddress();
70 }
71
72 @Override
73 public boolean isOpen() {
74 return state < 2;
75 }
76
77 @Override
78 public boolean isActive() {
79 return state == 1;
80 }
81
82 @Override
83 protected boolean isCompatible(EventLoop loop) {
84 return loop instanceof SingleThreadEventLoop;
85 }
86
87 @Override
88 protected SocketAddress localAddress0() {
89 return localAddress;
90 }
91
92 @Override
93 protected void doRegister() throws Exception {
94 ((SingleThreadEventExecutor) eventLoop()).addShutdownHook(shutdownHook);
95 }
96
97 @Override
98 protected void doBind(SocketAddress localAddress) throws Exception {
99 this.localAddress = LocalChannelRegistry.register(this, this.localAddress, localAddress);
100 state = 1;
101 }
102
103 @Override
104 protected void doClose() throws Exception {
105 if (state <= 1) {
106
107 if (localAddress != null) {
108 LocalChannelRegistry.unregister(localAddress);
109 localAddress = null;
110 }
111 state = 2;
112 }
113
114
115
116 Object m;
117 while ((m = inboundBuffer.poll()) != null) {
118 ((LocalChannel) m).unsafe().closeForcibly();
119 }
120 }
121
122 @Override
123 protected void doDeregister() throws Exception {
124 ((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook);
125 }
126
127 @Override
128 protected void doBeginRead() throws Exception {
129 if (acceptInProgress) {
130 return;
131 }
132
133 Queue<Object> inboundBuffer = this.inboundBuffer;
134 if (inboundBuffer.isEmpty()) {
135 acceptInProgress = true;
136 return;
137 }
138
139 readInbound();
140 }
141
142 LocalChannel serve(final LocalChannel peer) {
143 final LocalChannel child = newLocalChannel(peer);
144 if (eventLoop().inEventLoop()) {
145 serve0(child);
146 } else {
147 eventLoop().execute(new Runnable() {
148 @Override
149 public void run() {
150 serve0(child);
151 }
152 });
153 }
154 return child;
155 }
156
157 private void readInbound() {
158 RecvByteBufAllocator.Handle handle = unsafe().recvBufAllocHandle();
159 handle.reset(config());
160 ChannelPipeline pipeline = pipeline();
161 do {
162 Object m = inboundBuffer.poll();
163 if (m == null) {
164 break;
165 }
166 handle.incMessagesRead(1);
167 pipeline.fireChannelRead(m);
168 } while (handle.continueReading());
169 handle.readComplete();
170 pipeline.fireChannelReadComplete();
171 }
172
173
174
175
176
177 protected LocalChannel newLocalChannel(LocalChannel peer) {
178 return new LocalChannel(this, peer);
179 }
180
181 private void serve0(final LocalChannel child) {
182 if (!isOpen()) {
183 child.unsafe().closeForcibly();
184 return;
185 }
186 inboundBuffer.add(child);
187 if (acceptInProgress) {
188 acceptInProgress = false;
189
190 readInbound();
191 }
192 }
193 }