PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/jetty-8.1.5.v20120716/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD00.java

#
Java | 522 lines | 384 code | 74 blank | 64 comment | 27 complexity | 5b322f8126d2fa13b18b50e56f5435cf MD5 | raw file
Possible License(s): Apache-2.0
  1. /*******************************************************************************
  2. * Copyright (c) 2011 Intalio, Inc.
  3. * ======================================================================
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Apache License v2.0 which accompanies this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. *
  11. * The Apache License v2.0 is available at
  12. * http://www.opensource.org/licenses/apache2.0.php
  13. *
  14. * You may elect to redistribute this code under either of these licenses.
  15. *******************************************************************************/
  16. // ========================================================================
  17. // Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
  18. // ------------------------------------------------------------------------
  19. // All rights reserved. This program and the accompanying materials
  20. // are made available under the terms of the Eclipse Public License v1.0
  21. // and Apache License v2.0 which accompanies this distribution.
  22. // The Eclipse Public License is available at
  23. // http://www.eclipse.org/legal/epl-v10.html
  24. // The Apache License v2.0 is available at
  25. // http://www.opensource.org/licenses/apache2.0.php
  26. // You may elect to redistribute this code under either of these licenses.
  27. // ========================================================================
  28. package org.eclipse.jetty.websocket;
  29. import java.io.IOException;
  30. import java.security.MessageDigest;
  31. import java.security.NoSuchAlgorithmException;
  32. import java.util.Collections;
  33. import java.util.List;
  34. import org.eclipse.jetty.io.AbstractConnection;
  35. import org.eclipse.jetty.io.AsyncEndPoint;
  36. import org.eclipse.jetty.io.Buffer;
  37. import org.eclipse.jetty.io.ByteArrayBuffer;
  38. import org.eclipse.jetty.io.Connection;
  39. import org.eclipse.jetty.io.EndPoint;
  40. import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
  41. import org.eclipse.jetty.util.StringUtil;
  42. import org.eclipse.jetty.util.log.Log;
  43. import org.eclipse.jetty.util.log.Logger;
  44. import org.eclipse.jetty.websocket.WebSocket.OnFrame;
  45. public class WebSocketConnectionD00 extends AbstractConnection implements WebSocketConnection, WebSocket.FrameConnection
  46. {
  47. private static final Logger LOG = Log.getLogger(WebSocketConnectionD00.class);
  48. public final static byte LENGTH_FRAME=(byte)0x80;
  49. public final static byte SENTINEL_FRAME=(byte)0x00;
  50. private final WebSocketParser _parser;
  51. private final WebSocketGenerator _generator;
  52. private final WebSocket _websocket;
  53. private final String _protocol;
  54. private String _key1;
  55. private String _key2;
  56. private ByteArrayBuffer _hixieBytes;
  57. public WebSocketConnectionD00(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol)
  58. throws IOException
  59. {
  60. super(endpoint,timestamp);
  61. _endp.setMaxIdleTime(maxIdleTime);
  62. _websocket = websocket;
  63. _protocol=protocol;
  64. _generator = new WebSocketGeneratorD00(buffers, _endp);
  65. _parser = new WebSocketParserD00(buffers, endpoint, new FrameHandlerD00(_websocket));
  66. }
  67. /* ------------------------------------------------------------ */
  68. public org.eclipse.jetty.websocket.WebSocket.Connection getConnection()
  69. {
  70. return this;
  71. }
  72. /* ------------------------------------------------------------ */
  73. public void setHixieKeys(String key1,String key2)
  74. {
  75. _key1=key1;
  76. _key2=key2;
  77. _hixieBytes=new IndirectNIOBuffer(16);
  78. }
  79. /* ------------------------------------------------------------ */
  80. public Connection handle() throws IOException
  81. {
  82. try
  83. {
  84. // handle stupid hixie random bytes
  85. if (_hixieBytes!=null)
  86. {
  87. // take any available bytes from the parser buffer, which may have already been read
  88. Buffer buffer=_parser.getBuffer();
  89. if (buffer!=null && buffer.length()>0)
  90. {
  91. int l=buffer.length();
  92. if (l>(8-_hixieBytes.length()))
  93. l=8-_hixieBytes.length();
  94. _hixieBytes.put(buffer.peek(buffer.getIndex(),l));
  95. buffer.skip(l);
  96. }
  97. // while we are not blocked
  98. while(_endp.isOpen())
  99. {
  100. // do we now have enough
  101. if (_hixieBytes.length()==8)
  102. {
  103. // we have the silly random bytes
  104. // so let's work out the stupid 16 byte reply.
  105. doTheHixieHixieShake();
  106. _endp.flush(_hixieBytes);
  107. _hixieBytes=null;
  108. _endp.flush();
  109. break;
  110. }
  111. // no, then let's fill
  112. int filled=_endp.fill(_hixieBytes);
  113. if (filled<0)
  114. {
  115. _endp.flush();
  116. _endp.close();
  117. break;
  118. }
  119. }
  120. if (_websocket instanceof OnFrame)
  121. ((OnFrame)_websocket).onHandshake(this);
  122. _websocket.onOpen(this);
  123. return this;
  124. }
  125. // handle the framing protocol
  126. boolean progress=true;
  127. while (progress)
  128. {
  129. int flushed=_generator.flush();
  130. int filled=_parser.parseNext();
  131. progress = flushed>0 || filled>0;
  132. _endp.flush();
  133. if (_endp instanceof AsyncEndPoint && ((AsyncEndPoint)_endp).hasProgressed())
  134. progress=true;
  135. }
  136. }
  137. catch(IOException e)
  138. {
  139. LOG.debug(e);
  140. try
  141. {
  142. if (_endp.isOpen())
  143. _endp.close();
  144. }
  145. catch(IOException e2)
  146. {
  147. LOG.ignore(e2);
  148. }
  149. throw e;
  150. }
  151. finally
  152. {
  153. if (_endp.isOpen())
  154. {
  155. if (_endp.isInputShutdown() && _generator.isBufferEmpty())
  156. _endp.close();
  157. else
  158. checkWriteable();
  159. checkWriteable();
  160. }
  161. }
  162. return this;
  163. }
  164. /* ------------------------------------------------------------ */
  165. public void onInputShutdown() throws IOException
  166. {
  167. // TODO
  168. }
  169. /* ------------------------------------------------------------ */
  170. private void doTheHixieHixieShake()
  171. {
  172. byte[] result=WebSocketConnectionD00.doTheHixieHixieShake(
  173. WebSocketConnectionD00.hixieCrypt(_key1),
  174. WebSocketConnectionD00.hixieCrypt(_key2),
  175. _hixieBytes.asArray());
  176. _hixieBytes.clear();
  177. _hixieBytes.put(result);
  178. }
  179. /* ------------------------------------------------------------ */
  180. public boolean isOpen()
  181. {
  182. return _endp!=null&&_endp.isOpen();
  183. }
  184. /* ------------------------------------------------------------ */
  185. public boolean isIdle()
  186. {
  187. return _parser.isBufferEmpty() && _generator.isBufferEmpty();
  188. }
  189. /* ------------------------------------------------------------ */
  190. public boolean isSuspended()
  191. {
  192. return false;
  193. }
  194. /* ------------------------------------------------------------ */
  195. public void onClose()
  196. {
  197. _websocket.onClose(WebSocketConnectionD06.CLOSE_NORMAL,"");
  198. }
  199. /* ------------------------------------------------------------ */
  200. /**
  201. */
  202. public void sendMessage(String content) throws IOException
  203. {
  204. byte[] data = content.getBytes(StringUtil.__UTF8);
  205. _generator.addFrame((byte)0,SENTINEL_FRAME,data,0,data.length);
  206. _generator.flush();
  207. checkWriteable();
  208. }
  209. /* ------------------------------------------------------------ */
  210. public void sendMessage(byte[] data, int offset, int length) throws IOException
  211. {
  212. _generator.addFrame((byte)0,LENGTH_FRAME,data,offset,length);
  213. _generator.flush();
  214. checkWriteable();
  215. }
  216. /* ------------------------------------------------------------ */
  217. public boolean isMore(byte flags)
  218. {
  219. return (flags&0x8) != 0;
  220. }
  221. /* ------------------------------------------------------------ */
  222. /**
  223. * {@inheritDoc}
  224. */
  225. public void sendControl(byte code, byte[] content, int offset, int length) throws IOException
  226. {
  227. }
  228. /* ------------------------------------------------------------ */
  229. public void sendFrame(byte flags,byte opcode, byte[] content, int offset, int length) throws IOException
  230. {
  231. _generator.addFrame((byte)0,opcode,content,offset,length);
  232. _generator.flush();
  233. checkWriteable();
  234. }
  235. /* ------------------------------------------------------------ */
  236. public void close(int code, String message)
  237. {
  238. throw new UnsupportedOperationException();
  239. }
  240. /* ------------------------------------------------------------ */
  241. public void disconnect()
  242. {
  243. close();
  244. }
  245. /* ------------------------------------------------------------ */
  246. public void close()
  247. {
  248. try
  249. {
  250. _generator.flush();
  251. _endp.close();
  252. }
  253. catch(IOException e)
  254. {
  255. LOG.ignore(e);
  256. }
  257. }
  258. public void shutdown()
  259. {
  260. close();
  261. }
  262. /* ------------------------------------------------------------ */
  263. public void fillBuffersFrom(Buffer buffer)
  264. {
  265. _parser.fill(buffer);
  266. }
  267. /* ------------------------------------------------------------ */
  268. private void checkWriteable()
  269. {
  270. if (!_generator.isBufferEmpty() && _endp instanceof AsyncEndPoint)
  271. ((AsyncEndPoint)_endp).scheduleWrite();
  272. }
  273. /* ------------------------------------------------------------ */
  274. static long hixieCrypt(String key)
  275. {
  276. // Don't ask me what all this is about.
  277. // I think it's pretend secret stuff, kind of
  278. // like talking in pig latin!
  279. long number=0;
  280. int spaces=0;
  281. for (char c : key.toCharArray())
  282. {
  283. if (Character.isDigit(c))
  284. number=number*10+(c-'0');
  285. else if (c==' ')
  286. spaces++;
  287. }
  288. return number/spaces;
  289. }
  290. public static byte[] doTheHixieHixieShake(long key1,long key2,byte[] key3)
  291. {
  292. try
  293. {
  294. MessageDigest md = MessageDigest.getInstance("MD5");
  295. byte [] fodder = new byte[16];
  296. fodder[0]=(byte)(0xff&(key1>>24));
  297. fodder[1]=(byte)(0xff&(key1>>16));
  298. fodder[2]=(byte)(0xff&(key1>>8));
  299. fodder[3]=(byte)(0xff&key1);
  300. fodder[4]=(byte)(0xff&(key2>>24));
  301. fodder[5]=(byte)(0xff&(key2>>16));
  302. fodder[6]=(byte)(0xff&(key2>>8));
  303. fodder[7]=(byte)(0xff&key2);
  304. System.arraycopy(key3, 0, fodder, 8, 8);
  305. md.update(fodder);
  306. return md.digest();
  307. }
  308. catch (NoSuchAlgorithmException e)
  309. {
  310. throw new IllegalStateException(e);
  311. }
  312. }
  313. public void setMaxTextMessageSize(int size)
  314. {
  315. }
  316. public void setMaxIdleTime(int ms)
  317. {
  318. try
  319. {
  320. _endp.setMaxIdleTime(ms);
  321. }
  322. catch(IOException e)
  323. {
  324. LOG.warn(e);
  325. }
  326. }
  327. public void setMaxBinaryMessageSize(int size)
  328. {
  329. }
  330. public int getMaxTextMessageSize()
  331. {
  332. return -1;
  333. }
  334. public int getMaxIdleTime()
  335. {
  336. return _endp.getMaxIdleTime();
  337. }
  338. public int getMaxBinaryMessageSize()
  339. {
  340. return -1;
  341. }
  342. public String getProtocol()
  343. {
  344. return _protocol;
  345. }
  346. protected void onFrameHandshake()
  347. {
  348. if (_websocket instanceof OnFrame)
  349. {
  350. ((OnFrame)_websocket).onHandshake(this);
  351. }
  352. }
  353. protected void onWebsocketOpen()
  354. {
  355. _websocket.onOpen(this);
  356. }
  357. static class FrameHandlerD00 implements WebSocketParser.FrameHandler
  358. {
  359. final WebSocket _websocket;
  360. FrameHandlerD00(WebSocket websocket)
  361. {
  362. _websocket=websocket;
  363. }
  364. public void onFrame(byte flags, byte opcode, Buffer buffer)
  365. {
  366. try
  367. {
  368. byte[] array=buffer.array();
  369. if (opcode==0)
  370. {
  371. if (_websocket instanceof WebSocket.OnTextMessage)
  372. ((WebSocket.OnTextMessage)_websocket).onMessage(buffer.toString(StringUtil.__UTF8));
  373. }
  374. else
  375. {
  376. if (_websocket instanceof WebSocket.OnBinaryMessage)
  377. ((WebSocket.OnBinaryMessage)_websocket).onMessage(array,buffer.getIndex(),buffer.length());
  378. }
  379. }
  380. catch(Throwable th)
  381. {
  382. LOG.warn(th);
  383. }
  384. }
  385. public void close(int code,String message)
  386. {
  387. }
  388. }
  389. public boolean isMessageComplete(byte flags)
  390. {
  391. return true;
  392. }
  393. public byte binaryOpcode()
  394. {
  395. return LENGTH_FRAME;
  396. }
  397. public byte textOpcode()
  398. {
  399. return SENTINEL_FRAME;
  400. }
  401. public boolean isControl(byte opcode)
  402. {
  403. return false;
  404. }
  405. public boolean isText(byte opcode)
  406. {
  407. return (opcode&LENGTH_FRAME)==0;
  408. }
  409. public boolean isBinary(byte opcode)
  410. {
  411. return (opcode&LENGTH_FRAME)!=0;
  412. }
  413. public boolean isContinuation(byte opcode)
  414. {
  415. return false;
  416. }
  417. public boolean isClose(byte opcode)
  418. {
  419. return false;
  420. }
  421. public boolean isPing(byte opcode)
  422. {
  423. return false;
  424. }
  425. public boolean isPong(byte opcode)
  426. {
  427. return false;
  428. }
  429. public List<Extension> getExtensions()
  430. {
  431. return Collections.emptyList();
  432. }
  433. public byte continuationOpcode()
  434. {
  435. return 0;
  436. }
  437. public byte finMask()
  438. {
  439. return 0;
  440. }
  441. public void setAllowFrameFragmentation(boolean allowFragmentation)
  442. {
  443. }
  444. public boolean isAllowFrameFragmentation()
  445. {
  446. return false;
  447. }
  448. }