1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.websocket;
15
16 import java.io.IOException;
17 import java.security.SecureRandom;
18 import java.util.Random;
19
20 import org.eclipse.jetty.io.Buffer;
21 import org.eclipse.jetty.io.EndPoint;
22 import org.eclipse.jetty.io.EofException;
23 import org.eclipse.jetty.util.TypeUtil;
24
25
26
27
28
29
30
31
32
33 public class WebSocketGeneratorD7_9 implements WebSocketGenerator
34 {
35 final private WebSocketBuffers _buffers;
36 final private EndPoint _endp;
37 private Buffer _buffer;
38 private final byte[] _mask=new byte[4];
39 private int _m;
40 private boolean _opsent;
41 private final MaskGen _maskGen;
42
43 public interface MaskGen
44 {
45 void genMask(byte[] mask);
46 }
47
48 public static class NullMaskGen implements MaskGen
49 {
50 public void genMask(byte[] mask)
51 {
52 mask[0]=mask[1]=mask[2]=mask[3]=0;
53 }
54 }
55
56 public static class FixedMaskGen implements MaskGen
57 {
58 final byte[] _mask;
59 public FixedMaskGen()
60 {
61 _mask=new byte[]{(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff};
62 }
63
64 public FixedMaskGen(byte[] mask)
65 {
66 _mask=mask;
67 }
68
69 public void genMask(byte[] mask)
70 {
71 mask[0]=_mask[0];
72 mask[1]=_mask[1];
73 mask[2]=_mask[2];
74 mask[3]=_mask[3];
75 }
76 }
77
78 public static class RandomMaskGen implements MaskGen
79 {
80 final Random _random;
81 public RandomMaskGen()
82 {
83 _random=new SecureRandom();
84 }
85
86 public RandomMaskGen(Random random)
87 {
88 _random=random;
89 }
90
91 public void genMask(byte[] mask)
92 {
93 _random.nextBytes(mask);
94 }
95 }
96
97
98 public WebSocketGeneratorD7_9(WebSocketBuffers buffers, EndPoint endp)
99 {
100 _buffers=buffers;
101 _endp=endp;
102 _maskGen=null;
103 }
104
105 public WebSocketGeneratorD7_9(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
106 {
107 _buffers=buffers;
108 _endp=endp;
109 _maskGen=maskGen;
110 }
111
112 public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
113 {
114
115
116 boolean mask=_maskGen!=null;
117
118 if (_buffer==null)
119 _buffer=mask?_buffers.getBuffer():_buffers.getDirectBuffer();
120
121 boolean last=WebSocketConnectionD7_9.isLastFrame(flags);
122 byte orig=opcode;
123
124 int space=mask?14:10;
125
126 do
127 {
128 opcode = _opsent?WebSocketConnectionD7_9.OP_CONTINUATION:opcode;
129 opcode=(byte)(((0xf&flags)<<4)+(0xf&opcode));
130 _opsent=true;
131
132 int payload=length;
133 if (payload+space>_buffer.capacity())
134 {
135
136 opcode=(byte)(opcode&0x7F);
137 payload=_buffer.capacity()-space;
138 }
139 else if (last)
140 opcode= (byte)(opcode|0x80);
141
142
143 if (_buffer.space() <= space)
144 {
145 flushBuffer();
146 if (_buffer.space() <= space)
147 flush();
148 }
149
150
151 if (payload>0xffff)
152 {
153 _buffer.put(new byte[]{
154 opcode,
155 mask?(byte)0xff:(byte)0x7f,
156 (byte)((payload>>56)&0x7f),
157 (byte)((payload>>48)&0xff),
158 (byte)((payload>>40)&0xff),
159 (byte)((payload>>32)&0xff),
160 (byte)((payload>>24)&0xff),
161 (byte)((payload>>16)&0xff),
162 (byte)((payload>>8)&0xff),
163 (byte)(payload&0xff)});
164 }
165 else if (payload >=0x7e)
166 {
167 _buffer.put(new byte[]{
168 opcode,
169 mask?(byte)0xfe:(byte)0x7e,
170 (byte)(payload>>8),
171 (byte)(payload&0xff)});
172 }
173 else
174 {
175 _buffer.put(new byte[]{
176 opcode,
177 (byte)(mask?(0x80|payload):payload)});
178 }
179
180
181 if (mask)
182 {
183 _maskGen.genMask(_mask);
184 _m=0;
185 _buffer.put(_mask);
186 }
187
188
189
190 int remaining = payload;
191 while (remaining > 0)
192 {
193 _buffer.compact();
194 int chunk = remaining < _buffer.space() ? remaining : _buffer.space();
195
196 if (mask)
197 {
198 for (int i=0;i<chunk;i++)
199 _buffer.put((byte)(content[offset+ (payload-remaining)+i]^_mask[+_m++%4]));
200 }
201 else
202 _buffer.put(content, offset + (payload - remaining), chunk);
203
204 remaining -= chunk;
205 if (_buffer.space() > 0)
206 {
207
208 flushBuffer();
209 }
210 else
211 {
212
213 flush();
214 if (remaining == 0)
215 {
216
217 flushBuffer();
218 }
219 }
220 }
221 offset+=payload;
222 length-=payload;
223 }
224 while (length>0);
225 _opsent=!last;
226
227 if (_buffer!=null && _buffer.length()==0)
228 {
229 _buffers.returnBuffer(_buffer);
230 _buffer=null;
231 }
232 }
233
234 public synchronized int flushBuffer() throws IOException
235 {
236 if (!_endp.isOpen())
237 throw new EofException();
238
239 if (_buffer!=null)
240 return _endp.flush(_buffer);
241
242 return 0;
243 }
244
245 public synchronized int flush() throws IOException
246 {
247 if (_buffer==null)
248 return 0;
249 int result = flushBuffer();
250
251 if (!_endp.isBlocking())
252 {
253 long now = System.currentTimeMillis();
254 long end=now+_endp.getMaxIdleTime();
255 while (_buffer.length()>0)
256 {
257 boolean ready = _endp.blockWritable(end-now);
258 if (!ready)
259 {
260 now = System.currentTimeMillis();
261 if (now<end)
262 continue;
263 throw new IOException("Write timeout");
264 }
265
266 result += flushBuffer();
267 }
268 }
269 _buffer.compact();
270 return result;
271 }
272
273 public synchronized boolean isBufferEmpty()
274 {
275 return _buffer==null || _buffer.length()==0;
276 }
277
278 public synchronized void idle()
279 {
280 if (_buffer!=null && _buffer.length()==0)
281 {
282 _buffers.returnBuffer(_buffer);
283 _buffer=null;
284 }
285 }
286
287 }