1 package org.eclipse.jetty.websocket;
2
3 import java.io.IOException;
4
5 import org.eclipse.jetty.io.Buffer;
6 import org.eclipse.jetty.io.EndPoint;
7
8
9
10
11
12
13
14
15
16 public class WebSocketGenerator
17 {
18 final private WebSocketBuffers _buffers;
19 final private EndPoint _endp;
20 private Buffer _buffer;
21
22 public WebSocketGenerator(WebSocketBuffers buffers, EndPoint endp)
23 {
24 _buffers=buffers;
25 _endp=endp;
26 }
27
28 synchronized public void addFrame(byte frame,byte[] content, int blockFor) throws IOException
29 {
30 addFrame(frame,content,0,content.length,blockFor);
31 }
32
33 synchronized public void addFrame(byte frame,byte[] content, int offset, int length, int blockFor) throws IOException
34 {
35 if (_buffer==null)
36 _buffer=_buffers.getDirectBuffer();
37
38 if ((frame&0x80)==0x80)
39 {
40
41
42
43 if (length>2097152)
44 throw new IllegalArgumentException("too big");
45 int length_bytes=(length>16384)?3:(length>128)?2:1;
46 int needed=length+1+length_bytes;
47 checkSpace(needed,blockFor);
48
49 _buffer.put(frame);
50
51 switch (length_bytes)
52 {
53 case 3:
54 _buffer.put((byte)(0x80|(length>>14)));
55 case 2:
56 _buffer.put((byte)(0x80|(0x7f&(length>>7))));
57 case 1:
58 _buffer.put((byte)(0x7f&length));
59 }
60
61 _buffer.put(content,offset,length);
62 }
63 else
64 {
65
66 int needed=length+2;
67 checkSpace(needed,blockFor);
68
69 _buffer.put(frame);
70 _buffer.put(content,offset,length);
71 _buffer.put((byte)0xFF);
72 }
73 }
74
75 synchronized public void addFrame(byte frame, String content, int blockFor) throws IOException
76 {
77 Buffer byte_buffer=_buffers.getBuffer();
78 try
79 {
80 byte[] array=byte_buffer.array();
81
82 int chars = content.length();
83 int bytes = 0;
84 final int limit=array.length-6;
85
86 for (int i = 0; i < chars; i++)
87 {
88 int code = content.charAt(i);
89
90 if (bytes>=limit)
91 throw new IllegalArgumentException("frame too large");
92
93 if ((code & 0xffffff80) == 0)
94 {
95 array[bytes++]=(byte)(code);
96 }
97 else if((code&0xfffff800)==0)
98 {
99 array[bytes++]=(byte)(0xc0|(code>>6));
100 array[bytes++]=(byte)(0x80|(code&0x3f));
101 }
102 else if((code&0xffff0000)==0)
103 {
104 array[bytes++]=(byte)(0xe0|(code>>12));
105 array[bytes++]=(byte)(0x80|((code>>6)&0x3f));
106 array[bytes++]=(byte)(0x80|(code&0x3f));
107 }
108 else if((code&0xff200000)==0)
109 {
110 array[bytes++]=(byte)(0xf0|(code>>18));
111 array[bytes++]=(byte)(0x80|((code>>12)&0x3f));
112 array[bytes++]=(byte)(0x80|((code>>6)&0x3f));
113 array[bytes++]=(byte)(0x80|(code&0x3f));
114 }
115 else if((code&0xf4000000)==0)
116 {
117 array[bytes++]=(byte)(0xf8|(code>>24));
118 array[bytes++]=(byte)(0x80|((code>>18)&0x3f));
119 array[bytes++]=(byte)(0x80|((code>>12)&0x3f));
120 array[bytes++]=(byte)(0x80|((code>>6)&0x3f));
121 array[bytes++]=(byte)(0x80|(code&0x3f));
122 }
123 else if((code&0x80000000)==0)
124 {
125 array[bytes++]=(byte)(0xfc|(code>>30));
126 array[bytes++]=(byte)(0x80|((code>>24)&0x3f));
127 array[bytes++]=(byte)(0x80|((code>>18)&0x3f));
128 array[bytes++]=(byte)(0x80|((code>>12)&0x3f));
129 array[bytes++]=(byte)(0x80|((code>>6)&0x3f));
130 array[bytes++]=(byte)(0x80|(code&0x3f));
131 }
132 else
133 {
134 array[bytes++]=(byte)('?');
135 }
136 }
137 addFrame(frame,array,0,bytes,blockFor);
138 }
139 finally
140 {
141 _buffers.returnBuffer(byte_buffer);
142 }
143 }
144
145 private void checkSpace(int needed, long blockFor)
146 throws IOException
147 {
148 int space=_buffer.space();
149
150 if (space<needed)
151 {
152 if (_endp.isBlocking())
153 {
154 try
155 {
156 flushBuffer();
157 _buffer.compact();
158 space=_buffer.space();
159 }
160 catch(IOException e)
161 {
162 throw e;
163 }
164 }
165 else
166 {
167 flushBuffer();
168 _buffer.compact();
169 space=_buffer.space();
170
171 if (space<needed && _buffer.length()>0 && _endp.blockWritable(blockFor))
172 {
173 flushBuffer();
174 _buffer.compact();
175 space=_buffer.space();
176 }
177 }
178
179 if (space<needed)
180 {
181 _endp.close();
182 throw new IOException("Full Timeout");
183 }
184 }
185 }
186
187 synchronized public int flush(long blockFor)
188 {
189 return 0;
190 }
191
192 synchronized public int flush() throws IOException
193 {
194 int flushed = flushBuffer();
195 if (_buffer!=null && _buffer.length()==0)
196 {
197 _buffers.returnBuffer(_buffer);
198 _buffer=null;
199 }
200 return flushed;
201 }
202
203 private int flushBuffer() throws IOException
204 {
205 if (!_endp.isOpen())
206 return -1;
207
208 if (_buffer!=null)
209 {
210 int flushed =_endp.flush(_buffer);
211 if (flushed>0)
212 _buffer.skip(flushed);
213 return flushed;
214 }
215 return 0;
216 }
217
218 synchronized public boolean isBufferEmpty()
219 {
220 return _buffer==null || _buffer.length()==0;
221 }
222 }