77import java .nio .channels .SelectionKey ;
88import java .nio .channels .Selector ;
99import java .nio .channels .SocketChannel ;
10+ import java .security .MessageDigest ;
1011import java .security .NoSuchAlgorithmException ;
1112import java .util .Iterator ;
13+ import java .util .Random ;
1214import java .util .Set ;
1315
16+ import net .tootallnate .websocket .WebSocketListener .Draft ;
17+
1418/**
1519 * The <tt>WebSocketClient</tt> is an abstract class that expects a valid
1620 * "ws://" URI to connect to. When connected, an instance recieves important
@@ -32,7 +36,24 @@ public abstract class WebSocketClient implements Runnable, WebSocketListener {
3236 * The WebSocket instance this client object wraps.
3337 */
3438 private WebSocket conn ;
35-
39+ /**
40+ * @author The Websocket mode this client is in.
41+ */
42+ private Draft draft ;
43+ /**
44+ * Number 1 used in handshake
45+ */
46+ private int number1 =0 ;
47+ /** Number 2 used in handshake
48+ */
49+ private int number2 =0 ;
50+ /** Key3 used in handshake
51+ */
52+ private byte [] key3 ;
53+ public static enum Draft {
54+ DRAFT75 ,
55+ DRAFT76
56+ }
3657
3758 // CONSTRUCTOR /////////////////////////////////////////////////////////////
3859 /**
@@ -41,8 +62,9 @@ public abstract class WebSocketClient implements Runnable, WebSocketListener {
4162 * must call <var>connect</var> first to initiate the socket connection.
4263 * @param serverUri The <tt>URI</tt> of the WebSocket server to connect to.
4364 */
44- public WebSocketClient (URI serverUri ) {
65+ public WebSocketClient (URI serverUri , Draft draft ) {
4566 this .uri = serverUri ;
67+ this .draft = draft ;
4668 }
4769
4870 // PUBLIC INSTANCE METHODS /////////////////////////////////////////////////
@@ -104,10 +126,10 @@ public void run() {
104126 while (selector .select (500 ) > 0 ) {
105127
106128 Set <SelectionKey > keys = selector .selectedKeys ();
107- Iterator i = keys .iterator ();
129+ Iterator < SelectionKey > i = keys .iterator ();
108130
109131 while (i .hasNext ()) {
110- SelectionKey key = ( SelectionKey ) i .next ();
132+ SelectionKey key = i .next ();
111133 i .remove ();
112134
113135 // When 'conn' has connected to the host
@@ -119,17 +141,26 @@ public void run() {
119141 }
120142
121143 // Now send WebSocket client-side handshake
144+ Random r =new Random ();
145+ this .key3 =new byte [8 ];
122146 String path = "/" + uri .getPath ();
123147 String host = uri .getHost () + (port != WebSocket .DEFAULT_PORT ? ":" + port : "" );
124148 String origin = null ; // TODO: Make 'origin' configurable
125149 String request = "GET " + path + " HTTP/1.1\r \n " +
126150 "Upgrade: WebSocket\r \n " +
127151 "Connection: Upgrade\r \n " +
128152 "Host: " + host + "\r \n " +
129- "Origin: " + origin + "\r \n " +
153+ "Origin: " + origin + "\r \n " ;
154+ if (this .draft ==Draft .DRAFT76 )
155+ {
156+ request +="Sec-WebSocket-Key1: " + this .generateKey () + "\r \n " ;
157+ request +="Sec-WebSocket-Key2: " + this .generateKey () + "\r \n " ;
158+ r .nextBytes (this .key3 );
159+ }
130160 //extraHeaders.toString() +
131- "\r \n " ;
161+ request += "\r \n " ;
132162 conn .socketChannel ().write (ByteBuffer .wrap (request .getBytes (WebSocket .UTF8_CHARSET )));
163+ conn .socketChannel ().write (ByteBuffer .wrap (key3 ));
133164 }
134165
135166 // When 'conn' has recieved some data
@@ -145,7 +176,39 @@ public void run() {
145176 e .printStackTrace ();
146177 }
147178 }
148-
179+ private String generateKey (){
180+ Random r =new Random ();
181+ long maxNumber =4294967295L ;
182+ long spaces =r .nextInt (12 )+1 ;
183+ int max =new Long (maxNumber /spaces ).intValue ();
184+ max =Math .abs (max );
185+ int number =r .nextInt (max )+1 ;
186+ if (this .number1 ==0 ){
187+ this .number1 =number ;
188+ }
189+ else {
190+ this .number2 =number ;
191+ }
192+ long product =number *spaces ;
193+ String key =Long .toString (product );
194+ int numChars =r .nextInt (12 );
195+ for (int i =0 ;i <numChars ;i ++){
196+ int position =r .nextInt (key .length ());
197+ position =Math .abs (position );
198+ char randChar =(char )(r .nextInt (95 )+33 );
199+ //exclude numbers here
200+ if (randChar >= 48 && randChar <=57 ){
201+ randChar -=15 ;
202+ }
203+ key =new StringBuilder (key ).insert (position , randChar ).toString ();
204+ }
205+ for (int i =0 ;i <spaces ;i ++){
206+ int position =r .nextInt (key .length ()-1 )+1 ;
207+ position =Math .abs (position );
208+ key =new StringBuilder (key ).insert (position ,"\u0020 " ).toString ();
209+ }
210+ return key ;
211+ }
149212
150213 // WebSocketListener IMPLEMENTATION ////////////////////////////////////////
151214 /**
@@ -157,10 +220,41 @@ public void run() {
157220 * @return <var>true</var> if <var>handshake</var> is a valid WebSocket server
158221 * handshake, <var>false</var> otherwise.
159222 * @throws IOException When socket related I/O errors occur.
223+ * @throws NoSuchAlgorithmException
160224 */
161- public boolean onHandshakeRecieved (WebSocket conn , String handshake ,byte [] key3 ) throws IOException {
225+ public boolean onHandshakeRecieved (WebSocket conn , String handshake ,byte [] reply ) throws IOException , NoSuchAlgorithmException {
162226 // TODO: Do some parsing of the returned handshake, and close connection
163227 // (return false) if we recieved anything unexpected.
228+ if (this .draft ==Draft .DRAFT76 ){
229+ if (reply ==null ){
230+ return false ;
231+ }
232+ byte [] challenge =new byte []{
233+ (byte )( this .number1 >> 24 ),
234+ (byte )( (this .number1 << 8 ) >> 24 ),
235+ (byte )( (this .number1 << 16 ) >> 24 ),
236+ (byte )( (this .number1 << 24 ) >> 24 ),
237+ (byte )( this .number2 >> 24 ),
238+ (byte )( (this .number2 << 8 ) >> 24 ),
239+ (byte )( (this .number2 << 16 ) >> 24 ),
240+ (byte )( (this .number2 << 24 ) >> 24 ),
241+ this .key3 [0 ],
242+ this .key3 [1 ],
243+ this .key3 [2 ],
244+ this .key3 [3 ],
245+ this .key3 [4 ],
246+ this .key3 [5 ],
247+ this .key3 [6 ],
248+ this .key3 [7 ]
249+ };
250+ MessageDigest md5 =MessageDigest .getInstance ("MD5" );
251+ byte [] expected =md5 .digest (challenge );
252+ for (int i =0 ;i <reply .length ;i ++){
253+ if (expected [i ]!=reply [i ]){
254+ return false ;
255+ }
256+ }
257+ }
164258 return true ;
165259 }
166260
@@ -188,7 +282,11 @@ public void onOpen(WebSocket conn) {
188282 public void onClose (WebSocket conn ) {
189283 onClose ();
190284 }
191-
285+
286+ @ Override
287+ public net .tootallnate .websocket .WebSocketListener .Draft getDraft () {
288+ return (net .tootallnate .websocket .WebSocketListener .Draft )net .tootallnate .websocket .WebSocketListener .Draft .valueOf (this .draft .name ());
289+ }
192290
193291 // ABTRACT METHODS /////////////////////////////////////////////////////////
194292 public abstract void onMessage (String message );
0 commit comments