1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.common.extensions.mux;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.net.URI;
24 import java.nio.ByteBuffer;
25 import java.util.concurrent.Future;
26 import java.util.concurrent.atomic.AtomicBoolean;
27
28 import org.eclipse.jetty.util.BufferUtil;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.websocket.api.StatusCode;
32 import org.eclipse.jetty.websocket.api.SuspendToken;
33 import org.eclipse.jetty.websocket.api.WebSocketConnection;
34 import org.eclipse.jetty.websocket.api.WebSocketException;
35 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
36 import org.eclipse.jetty.websocket.api.WriteCallback;
37 import org.eclipse.jetty.websocket.api.extensions.Frame;
38 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
39 import org.eclipse.jetty.websocket.common.CloseInfo;
40 import org.eclipse.jetty.websocket.common.ConnectionState;
41 import org.eclipse.jetty.websocket.common.LogicalConnection;
42 import org.eclipse.jetty.websocket.common.WebSocketFrame;
43 import org.eclipse.jetty.websocket.common.WebSocketSession;
44 import org.eclipse.jetty.websocket.common.io.FutureWriteCallback;
45 import org.eclipse.jetty.websocket.common.io.IOState;
46
47
48
49
50 public class MuxChannel implements WebSocketConnection, LogicalConnection, IncomingFrames, SuspendToken
51 {
52 private static final Logger LOG = Log.getLogger(MuxChannel.class);
53
54 private final long channelId;
55 private final Muxer muxer;
56 private final AtomicBoolean inputClosed;
57 private final AtomicBoolean outputClosed;
58 private final AtomicBoolean suspendToken;
59 private IOState ioState;
60 private WebSocketPolicy policy;
61 private WebSocketSession session;
62 private IncomingFrames incoming;
63 private String subProtocol;
64
65 public MuxChannel(long channelId, Muxer muxer)
66 {
67 this.channelId = channelId;
68 this.muxer = muxer;
69 this.policy = muxer.getPolicy().clonePolicy();
70
71 this.suspendToken = new AtomicBoolean(false);
72 this.ioState = new IOState();
73 ioState.setState(ConnectionState.CONNECTING);
74
75 this.inputClosed = new AtomicBoolean(false);
76 this.outputClosed = new AtomicBoolean(false);
77 }
78
79 @Override
80 public void close()
81 {
82 close(StatusCode.NORMAL,null);
83 }
84
85 @Override
86 public void close(int statusCode, String reason)
87 {
88 CloseInfo close = new CloseInfo(statusCode,reason);
89
90 outgoingFrame(close.asFrame(),null);
91 }
92
93 @Override
94 public void disconnect()
95 {
96 this.ioState.setState(ConnectionState.CLOSED);
97
98 }
99
100 public long getChannelId()
101 {
102 return channelId;
103 }
104
105 @Override
106 public IOState getIOState()
107 {
108
109 return null;
110 }
111
112 @Override
113 public InetSocketAddress getLocalAddress()
114 {
115
116 return null;
117 }
118
119 @Override
120 public WebSocketPolicy getPolicy()
121 {
122 return policy;
123 }
124
125 @Override
126 public InetSocketAddress getRemoteAddress()
127 {
128 return muxer.getRemoteAddress();
129 }
130
131 @Override
132 public URI getRequestURI()
133 {
134
135 return null;
136 }
137
138 @Override
139 public WebSocketSession getSession()
140 {
141 return session;
142 }
143
144 @Override
145 public String getSubProtocol()
146 {
147 return this.subProtocol;
148 }
149
150
151
152
153 @Override
154 public void incomingError(WebSocketException e)
155 {
156 incoming.incomingError(e);
157 }
158
159
160
161
162 @Override
163 public void incomingFrame(Frame frame)
164 {
165 incoming.incomingFrame(frame);
166 }
167
168 public boolean isActive()
169 {
170 return (ioState.isOpen());
171 }
172
173 @Override
174 public boolean isOpen()
175 {
176 return isActive() && muxer.isOpen();
177 }
178
179 @Override
180 public boolean isReading()
181 {
182 return true;
183 }
184
185 public void onClose()
186 {
187 this.ioState.setState(ConnectionState.CLOSED);
188 }
189
190 public void onOpen()
191 {
192 this.ioState.setState(ConnectionState.OPEN);
193 }
194
195
196
197
198
199
200
201 private Future<Void> outgoingAsyncFrame(WebSocketFrame frame)
202 {
203 FutureWriteCallback future = new FutureWriteCallback();
204 outgoingFrame(frame,future);
205 return future;
206 }
207
208
209
210
211 @Override
212 public void outgoingFrame(Frame frame, WriteCallback callback)
213 {
214 muxer.output(channelId,frame,callback);
215 }
216
217
218
219
220 @Override
221 public void ping(ByteBuffer buf) throws IOException
222 {
223 outgoingFrame(WebSocketFrame.ping().setPayload(buf),null);
224 }
225
226 @Override
227 public void resume()
228 {
229 if (suspendToken.getAndSet(false))
230 {
231
232 }
233 }
234
235 @Override
236 public void setNextIncomingFrames(IncomingFrames incoming)
237 {
238 this.incoming = incoming;
239 }
240
241 @Override
242 public void setSession(WebSocketSession session)
243 {
244 this.session = session;
245
246 }
247
248 public void setSubProtocol(String subProtocol)
249 {
250 this.subProtocol = subProtocol;
251 }
252
253 @Override
254 public SuspendToken suspend()
255 {
256 suspendToken.set(true);
257
258 return this;
259 }
260
261
262
263
264 @Override
265 public Future<Void> write(byte[] buf, int offset, int len)
266 {
267 ByteBuffer bb = ByteBuffer.wrap(buf,offset,len);
268 return write(bb);
269 }
270
271
272
273
274 @Override
275 public Future<Void> write(ByteBuffer buffer)
276 {
277 if (LOG.isDebugEnabled())
278 {
279 LOG.debug("write with {}",BufferUtil.toDetailString(buffer));
280 }
281 WebSocketFrame frame = WebSocketFrame.binary().setPayload(buffer);
282 return outgoingAsyncFrame(frame);
283 }
284
285
286
287
288 @Override
289 public Future<Void> write(String message)
290 {
291 return outgoingAsyncFrame(WebSocketFrame.text(message));
292 }
293 }