103928aee4356845252ac6b662d5c72c29903813eJake Slack// 203928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 303928aee4356845252ac6b662d5c72c29903813eJake Slack// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 403928aee4356845252ac6b662d5c72c29903813eJake Slack// ------------------------------------------------------------------------ 503928aee4356845252ac6b662d5c72c29903813eJake Slack// All rights reserved. This program and the accompanying materials 603928aee4356845252ac6b662d5c72c29903813eJake Slack// are made available under the terms of the Eclipse Public License v1.0 703928aee4356845252ac6b662d5c72c29903813eJake Slack// and Apache License v2.0 which accompanies this distribution. 803928aee4356845252ac6b662d5c72c29903813eJake Slack// 903928aee4356845252ac6b662d5c72c29903813eJake Slack// The Eclipse Public License is available at 1003928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.eclipse.org/legal/epl-v10.html 1103928aee4356845252ac6b662d5c72c29903813eJake Slack// 1203928aee4356845252ac6b662d5c72c29903813eJake Slack// The Apache License v2.0 is available at 1303928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.opensource.org/licenses/apache2.0.php 1403928aee4356845252ac6b662d5c72c29903813eJake Slack// 1503928aee4356845252ac6b662d5c72c29903813eJake Slack// You may elect to redistribute this code under either of these licenses. 1603928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 1703928aee4356845252ac6b662d5c72c29903813eJake Slack// 1803928aee4356845252ac6b662d5c72c29903813eJake Slack 1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.websocket; 2003928aee4356845252ac6b662d5c72c29903813eJake Slack 2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.EOFException; 2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException; 2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.net.ProtocolException; 2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.nio.channels.SelectionKey; 2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.nio.channels.SocketChannel; 2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.List; 2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Map; 2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Queue; 2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Random; 3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.ConcurrentLinkedQueue; 3103928aee4356845252ac6b662d5c72c29903813eJake Slack 3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.net.ssl.SSLEngine; 3303928aee4356845252ac6b662d5c72c29903813eJake Slack 3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpFields; 3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpParser; 3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.AbstractConnection; 3703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.AsyncEndPoint; 3803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffer; 3903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffers; 4003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ByteArrayBuffer; 4103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ConnectedEndPoint; 4203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Connection; 4303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.EndPoint; 4403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.SimpleBuffers; 4503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.AsyncConnection; 4603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.SelectChannelEndPoint; 4703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.SelectorManager; 4803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.nio.SslConnection; 4903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.B64Code; 5003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.QuotedStringTokenizer; 5103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.component.AggregateLifeCycle; 5203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger; 5303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.ssl.SslContextFactory; 5403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.thread.QueuedThreadPool; 5503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.thread.ThreadPool; 5603928aee4356845252ac6b662d5c72c29903813eJake Slack 5703928aee4356845252ac6b662d5c72c29903813eJake Slack/* ------------------------------------------------------------ */ 5803928aee4356845252ac6b662d5c72c29903813eJake Slack/** 5903928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>WebSocketClientFactory contains the common components needed by multiple {@link WebSocketClient} instances 6003928aee4356845252ac6b662d5c72c29903813eJake Slack * (for example, a {@link ThreadPool}, a {@link SelectorManager NIO selector}, etc).</p> 6103928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>WebSocketClients with different configurations should share the same factory to avoid to waste resources.</p> 6203928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>If a ThreadPool or MaskGen is passed in the constructor, then it is not added with {@link AggregateLifeCycle#addBean(Object)}, 6303928aee4356845252ac6b662d5c72c29903813eJake Slack * so it's lifecycle must be controlled externally. 6403928aee4356845252ac6b662d5c72c29903813eJake Slack * 6503928aee4356845252ac6b662d5c72c29903813eJake Slack * @see WebSocketClient 6603928aee4356845252ac6b662d5c72c29903813eJake Slack */ 6703928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class WebSocketClientFactory extends AggregateLifeCycle 6803928aee4356845252ac6b662d5c72c29903813eJake Slack{ 6903928aee4356845252ac6b662d5c72c29903813eJake Slack private final static Logger __log = org.eclipse.jetty.util.log.Log.getLogger(WebSocketClientFactory.class.getName()); 7003928aee4356845252ac6b662d5c72c29903813eJake Slack private final static ByteArrayBuffer __ACCEPT = new ByteArrayBuffer.CaseInsensitive("Sec-WebSocket-Accept"); 7103928aee4356845252ac6b662d5c72c29903813eJake Slack private final Queue<WebSocketConnection> connections = new ConcurrentLinkedQueue<WebSocketConnection>(); 7203928aee4356845252ac6b662d5c72c29903813eJake Slack private final SslContextFactory _sslContextFactory = new SslContextFactory(); 7303928aee4356845252ac6b662d5c72c29903813eJake Slack private final ThreadPool _threadPool; 7403928aee4356845252ac6b662d5c72c29903813eJake Slack private final WebSocketClientSelector _selector; 7503928aee4356845252ac6b662d5c72c29903813eJake Slack private MaskGen _maskGen; 7603928aee4356845252ac6b662d5c72c29903813eJake Slack private WebSocketBuffers _buffers; 7703928aee4356845252ac6b662d5c72c29903813eJake Slack 7803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 7903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 8003928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>Creates a WebSocketClientFactory with the default configuration.</p> 8103928aee4356845252ac6b662d5c72c29903813eJake Slack */ 8203928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClientFactory() 8303928aee4356845252ac6b662d5c72c29903813eJake Slack { 8403928aee4356845252ac6b662d5c72c29903813eJake Slack this(null); 8503928aee4356845252ac6b662d5c72c29903813eJake Slack } 8603928aee4356845252ac6b662d5c72c29903813eJake Slack 8703928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 8803928aee4356845252ac6b662d5c72c29903813eJake Slack /** 8903928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>Creates a WebSocketClientFactory with the given ThreadPool and the default configuration.</p> 9003928aee4356845252ac6b662d5c72c29903813eJake Slack * 9103928aee4356845252ac6b662d5c72c29903813eJake Slack * @param threadPool the ThreadPool instance to use 9203928aee4356845252ac6b662d5c72c29903813eJake Slack */ 9303928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClientFactory(ThreadPool threadPool) 9403928aee4356845252ac6b662d5c72c29903813eJake Slack { 9503928aee4356845252ac6b662d5c72c29903813eJake Slack this(threadPool, new RandomMaskGen()); 9603928aee4356845252ac6b662d5c72c29903813eJake Slack } 9703928aee4356845252ac6b662d5c72c29903813eJake Slack 9803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 9903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 10003928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>Creates a WebSocketClientFactory with the given ThreadPool and the given MaskGen.</p> 10103928aee4356845252ac6b662d5c72c29903813eJake Slack * 10203928aee4356845252ac6b662d5c72c29903813eJake Slack * @param threadPool the ThreadPool instance to use 10303928aee4356845252ac6b662d5c72c29903813eJake Slack * @param maskGen the MaskGen instance to use 10403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 10503928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClientFactory(ThreadPool threadPool, MaskGen maskGen) 10603928aee4356845252ac6b662d5c72c29903813eJake Slack { 10703928aee4356845252ac6b662d5c72c29903813eJake Slack this(threadPool, maskGen, 8192); 10803928aee4356845252ac6b662d5c72c29903813eJake Slack } 10903928aee4356845252ac6b662d5c72c29903813eJake Slack 11003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 11103928aee4356845252ac6b662d5c72c29903813eJake Slack 11203928aee4356845252ac6b662d5c72c29903813eJake Slack /** 11303928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>Creates a WebSocketClientFactory with the specified configuration.</p> 11403928aee4356845252ac6b662d5c72c29903813eJake Slack * 11503928aee4356845252ac6b662d5c72c29903813eJake Slack * @param threadPool the ThreadPool instance to use 11603928aee4356845252ac6b662d5c72c29903813eJake Slack * @param maskGen the mask generator to use 11703928aee4356845252ac6b662d5c72c29903813eJake Slack * @param bufferSize the read buffer size 11803928aee4356845252ac6b662d5c72c29903813eJake Slack */ 11903928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClientFactory(ThreadPool threadPool, MaskGen maskGen, int bufferSize) 12003928aee4356845252ac6b662d5c72c29903813eJake Slack { 12103928aee4356845252ac6b662d5c72c29903813eJake Slack if (threadPool == null) 12203928aee4356845252ac6b662d5c72c29903813eJake Slack threadPool = new QueuedThreadPool(); 12303928aee4356845252ac6b662d5c72c29903813eJake Slack _threadPool = threadPool; 12403928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_threadPool); 12503928aee4356845252ac6b662d5c72c29903813eJake Slack 12603928aee4356845252ac6b662d5c72c29903813eJake Slack _buffers = new WebSocketBuffers(bufferSize); 12703928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_buffers); 12803928aee4356845252ac6b662d5c72c29903813eJake Slack 12903928aee4356845252ac6b662d5c72c29903813eJake Slack _maskGen = maskGen; 13003928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_maskGen); 13103928aee4356845252ac6b662d5c72c29903813eJake Slack 13203928aee4356845252ac6b662d5c72c29903813eJake Slack _selector = new WebSocketClientSelector(); 13303928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_selector); 13403928aee4356845252ac6b662d5c72c29903813eJake Slack 13503928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_sslContextFactory); 13603928aee4356845252ac6b662d5c72c29903813eJake Slack } 13703928aee4356845252ac6b662d5c72c29903813eJake Slack 13803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 13903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 14003928aee4356845252ac6b662d5c72c29903813eJake Slack * @return the SslContextFactory used to configure SSL parameters 14103928aee4356845252ac6b662d5c72c29903813eJake Slack */ 14203928aee4356845252ac6b662d5c72c29903813eJake Slack public SslContextFactory getSslContextFactory() 14303928aee4356845252ac6b662d5c72c29903813eJake Slack { 14403928aee4356845252ac6b662d5c72c29903813eJake Slack return _sslContextFactory; 14503928aee4356845252ac6b662d5c72c29903813eJake Slack } 14603928aee4356845252ac6b662d5c72c29903813eJake Slack 14703928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 14803928aee4356845252ac6b662d5c72c29903813eJake Slack /** 14903928aee4356845252ac6b662d5c72c29903813eJake Slack * Get the selectorManager. Used to configure the manager. 15003928aee4356845252ac6b662d5c72c29903813eJake Slack * 15103928aee4356845252ac6b662d5c72c29903813eJake Slack * @return The {@link SelectorManager} instance. 15203928aee4356845252ac6b662d5c72c29903813eJake Slack */ 15303928aee4356845252ac6b662d5c72c29903813eJake Slack public SelectorManager getSelectorManager() 15403928aee4356845252ac6b662d5c72c29903813eJake Slack { 15503928aee4356845252ac6b662d5c72c29903813eJake Slack return _selector; 15603928aee4356845252ac6b662d5c72c29903813eJake Slack } 15703928aee4356845252ac6b662d5c72c29903813eJake Slack 15803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 15903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 16003928aee4356845252ac6b662d5c72c29903813eJake Slack * Get the ThreadPool. 16103928aee4356845252ac6b662d5c72c29903813eJake Slack * Used to set/query the thread pool configuration. 16203928aee4356845252ac6b662d5c72c29903813eJake Slack * 16303928aee4356845252ac6b662d5c72c29903813eJake Slack * @return The {@link ThreadPool} 16403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 16503928aee4356845252ac6b662d5c72c29903813eJake Slack public ThreadPool getThreadPool() 16603928aee4356845252ac6b662d5c72c29903813eJake Slack { 16703928aee4356845252ac6b662d5c72c29903813eJake Slack return _threadPool; 16803928aee4356845252ac6b662d5c72c29903813eJake Slack } 16903928aee4356845252ac6b662d5c72c29903813eJake Slack 17003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 17103928aee4356845252ac6b662d5c72c29903813eJake Slack /** 17203928aee4356845252ac6b662d5c72c29903813eJake Slack * @return the shared mask generator, or null if no shared mask generator is used 17303928aee4356845252ac6b662d5c72c29903813eJake Slack * @see WebSocketClient#getMaskGen() 17403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 17503928aee4356845252ac6b662d5c72c29903813eJake Slack public MaskGen getMaskGen() 17603928aee4356845252ac6b662d5c72c29903813eJake Slack { 17703928aee4356845252ac6b662d5c72c29903813eJake Slack return _maskGen; 17803928aee4356845252ac6b662d5c72c29903813eJake Slack } 17903928aee4356845252ac6b662d5c72c29903813eJake Slack 18003928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 18103928aee4356845252ac6b662d5c72c29903813eJake Slack /** 18203928aee4356845252ac6b662d5c72c29903813eJake Slack * @param maskGen the shared mask generator, or null if no shared mask generator is used 18303928aee4356845252ac6b662d5c72c29903813eJake Slack * @see WebSocketClient#setMaskGen(MaskGen) 18403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 18503928aee4356845252ac6b662d5c72c29903813eJake Slack public void setMaskGen(MaskGen maskGen) 18603928aee4356845252ac6b662d5c72c29903813eJake Slack { 18703928aee4356845252ac6b662d5c72c29903813eJake Slack if (isRunning()) 18803928aee4356845252ac6b662d5c72c29903813eJake Slack throw new IllegalStateException(getState()); 18903928aee4356845252ac6b662d5c72c29903813eJake Slack removeBean(_maskGen); 19003928aee4356845252ac6b662d5c72c29903813eJake Slack _maskGen = maskGen; 19103928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(maskGen); 19203928aee4356845252ac6b662d5c72c29903813eJake Slack } 19303928aee4356845252ac6b662d5c72c29903813eJake Slack 19403928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 19503928aee4356845252ac6b662d5c72c29903813eJake Slack /** 19603928aee4356845252ac6b662d5c72c29903813eJake Slack * @param bufferSize the read buffer size 19703928aee4356845252ac6b662d5c72c29903813eJake Slack * @see #getBufferSize() 19803928aee4356845252ac6b662d5c72c29903813eJake Slack */ 19903928aee4356845252ac6b662d5c72c29903813eJake Slack public void setBufferSize(int bufferSize) 20003928aee4356845252ac6b662d5c72c29903813eJake Slack { 20103928aee4356845252ac6b662d5c72c29903813eJake Slack if (isRunning()) 20203928aee4356845252ac6b662d5c72c29903813eJake Slack throw new IllegalStateException(getState()); 20303928aee4356845252ac6b662d5c72c29903813eJake Slack removeBean(_buffers); 20403928aee4356845252ac6b662d5c72c29903813eJake Slack _buffers = new WebSocketBuffers(bufferSize); 20503928aee4356845252ac6b662d5c72c29903813eJake Slack addBean(_buffers); 20603928aee4356845252ac6b662d5c72c29903813eJake Slack } 20703928aee4356845252ac6b662d5c72c29903813eJake Slack 20803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 20903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 21003928aee4356845252ac6b662d5c72c29903813eJake Slack * @return the read buffer size 21103928aee4356845252ac6b662d5c72c29903813eJake Slack */ 21203928aee4356845252ac6b662d5c72c29903813eJake Slack public int getBufferSize() 21303928aee4356845252ac6b662d5c72c29903813eJake Slack { 21403928aee4356845252ac6b662d5c72c29903813eJake Slack return _buffers.getBufferSize(); 21503928aee4356845252ac6b662d5c72c29903813eJake Slack } 21603928aee4356845252ac6b662d5c72c29903813eJake Slack 21703928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 21803928aee4356845252ac6b662d5c72c29903813eJake Slack protected void doStop() throws Exception 21903928aee4356845252ac6b662d5c72c29903813eJake Slack { 22003928aee4356845252ac6b662d5c72c29903813eJake Slack closeConnections(); 22103928aee4356845252ac6b662d5c72c29903813eJake Slack super.doStop(); 22203928aee4356845252ac6b662d5c72c29903813eJake Slack } 22303928aee4356845252ac6b662d5c72c29903813eJake Slack 22403928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 22503928aee4356845252ac6b662d5c72c29903813eJake Slack /** 22603928aee4356845252ac6b662d5c72c29903813eJake Slack * <p>Creates and returns a new instance of a {@link WebSocketClient}, configured with this 22703928aee4356845252ac6b662d5c72c29903813eJake Slack * WebSocketClientFactory instance.</p> 22803928aee4356845252ac6b662d5c72c29903813eJake Slack * 22903928aee4356845252ac6b662d5c72c29903813eJake Slack * @return a new {@link WebSocketClient} instance 23003928aee4356845252ac6b662d5c72c29903813eJake Slack */ 23103928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClient newWebSocketClient() 23203928aee4356845252ac6b662d5c72c29903813eJake Slack { 23303928aee4356845252ac6b662d5c72c29903813eJake Slack return new WebSocketClient(this); 23403928aee4356845252ac6b662d5c72c29903813eJake Slack } 23503928aee4356845252ac6b662d5c72c29903813eJake Slack 23603928aee4356845252ac6b662d5c72c29903813eJake Slack protected SSLEngine newSslEngine(SocketChannel channel) throws IOException 23703928aee4356845252ac6b662d5c72c29903813eJake Slack { 23803928aee4356845252ac6b662d5c72c29903813eJake Slack SSLEngine sslEngine; 23903928aee4356845252ac6b662d5c72c29903813eJake Slack if (channel != null) 24003928aee4356845252ac6b662d5c72c29903813eJake Slack { 24103928aee4356845252ac6b662d5c72c29903813eJake Slack String peerHost = channel.socket().getInetAddress().getHostAddress(); 24203928aee4356845252ac6b662d5c72c29903813eJake Slack int peerPort = channel.socket().getPort(); 24303928aee4356845252ac6b662d5c72c29903813eJake Slack sslEngine = _sslContextFactory.newSslEngine(peerHost, peerPort); 24403928aee4356845252ac6b662d5c72c29903813eJake Slack } 24503928aee4356845252ac6b662d5c72c29903813eJake Slack else 24603928aee4356845252ac6b662d5c72c29903813eJake Slack { 24703928aee4356845252ac6b662d5c72c29903813eJake Slack sslEngine = _sslContextFactory.newSslEngine(); 24803928aee4356845252ac6b662d5c72c29903813eJake Slack } 24903928aee4356845252ac6b662d5c72c29903813eJake Slack sslEngine.setUseClientMode(true); 25003928aee4356845252ac6b662d5c72c29903813eJake Slack sslEngine.beginHandshake(); 25103928aee4356845252ac6b662d5c72c29903813eJake Slack 25203928aee4356845252ac6b662d5c72c29903813eJake Slack return sslEngine; 25303928aee4356845252ac6b662d5c72c29903813eJake Slack } 25403928aee4356845252ac6b662d5c72c29903813eJake Slack 25503928aee4356845252ac6b662d5c72c29903813eJake Slack protected boolean addConnection(WebSocketConnection connection) 25603928aee4356845252ac6b662d5c72c29903813eJake Slack { 25703928aee4356845252ac6b662d5c72c29903813eJake Slack return isRunning() && connections.add(connection); 25803928aee4356845252ac6b662d5c72c29903813eJake Slack } 25903928aee4356845252ac6b662d5c72c29903813eJake Slack 26003928aee4356845252ac6b662d5c72c29903813eJake Slack protected boolean removeConnection(WebSocketConnection connection) 26103928aee4356845252ac6b662d5c72c29903813eJake Slack { 26203928aee4356845252ac6b662d5c72c29903813eJake Slack return connections.remove(connection); 26303928aee4356845252ac6b662d5c72c29903813eJake Slack } 26403928aee4356845252ac6b662d5c72c29903813eJake Slack 26503928aee4356845252ac6b662d5c72c29903813eJake Slack protected void closeConnections() 26603928aee4356845252ac6b662d5c72c29903813eJake Slack { 26703928aee4356845252ac6b662d5c72c29903813eJake Slack for (WebSocketConnection connection : connections) 26803928aee4356845252ac6b662d5c72c29903813eJake Slack connection.shutdown(); 26903928aee4356845252ac6b662d5c72c29903813eJake Slack } 27003928aee4356845252ac6b662d5c72c29903813eJake Slack 27103928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 27203928aee4356845252ac6b662d5c72c29903813eJake Slack /** 27303928aee4356845252ac6b662d5c72c29903813eJake Slack * WebSocket Client Selector Manager 27403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 27503928aee4356845252ac6b662d5c72c29903813eJake Slack class WebSocketClientSelector extends SelectorManager 27603928aee4356845252ac6b662d5c72c29903813eJake Slack { 27703928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 27803928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean dispatch(Runnable task) 27903928aee4356845252ac6b662d5c72c29903813eJake Slack { 28003928aee4356845252ac6b662d5c72c29903813eJake Slack return _threadPool.dispatch(task); 28103928aee4356845252ac6b662d5c72c29903813eJake Slack } 28203928aee4356845252ac6b662d5c72c29903813eJake Slack 28303928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 28403928aee4356845252ac6b662d5c72c29903813eJake Slack protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, final SelectionKey key) throws IOException 28503928aee4356845252ac6b662d5c72c29903813eJake Slack { 28603928aee4356845252ac6b662d5c72c29903813eJake Slack WebSocketClient.WebSocketFuture holder = (WebSocketClient.WebSocketFuture)key.attachment(); 28703928aee4356845252ac6b662d5c72c29903813eJake Slack int maxIdleTime = holder.getMaxIdleTime(); 28803928aee4356845252ac6b662d5c72c29903813eJake Slack if (maxIdleTime < 0) 28903928aee4356845252ac6b662d5c72c29903813eJake Slack maxIdleTime = (int)getMaxIdleTime(); 29003928aee4356845252ac6b662d5c72c29903813eJake Slack SelectChannelEndPoint result = new SelectChannelEndPoint(channel, selectSet, key, maxIdleTime); 29103928aee4356845252ac6b662d5c72c29903813eJake Slack AsyncEndPoint endPoint = result; 29203928aee4356845252ac6b662d5c72c29903813eJake Slack 29303928aee4356845252ac6b662d5c72c29903813eJake Slack // Detect if it is SSL, and wrap the connection if so 29403928aee4356845252ac6b662d5c72c29903813eJake Slack if ("wss".equals(holder.getURI().getScheme())) 29503928aee4356845252ac6b662d5c72c29903813eJake Slack { 29603928aee4356845252ac6b662d5c72c29903813eJake Slack SSLEngine sslEngine = newSslEngine(channel); 29703928aee4356845252ac6b662d5c72c29903813eJake Slack SslConnection sslConnection = new SslConnection(sslEngine, endPoint); 29803928aee4356845252ac6b662d5c72c29903813eJake Slack endPoint.setConnection(sslConnection); 29903928aee4356845252ac6b662d5c72c29903813eJake Slack endPoint = sslConnection.getSslEndPoint(); 30003928aee4356845252ac6b662d5c72c29903813eJake Slack } 30103928aee4356845252ac6b662d5c72c29903813eJake Slack 30203928aee4356845252ac6b662d5c72c29903813eJake Slack AsyncConnection connection = selectSet.getManager().newConnection(channel, endPoint, holder); 30303928aee4356845252ac6b662d5c72c29903813eJake Slack endPoint.setConnection(connection); 30403928aee4356845252ac6b662d5c72c29903813eJake Slack 30503928aee4356845252ac6b662d5c72c29903813eJake Slack return result; 30603928aee4356845252ac6b662d5c72c29903813eJake Slack } 30703928aee4356845252ac6b662d5c72c29903813eJake Slack 30803928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 30903928aee4356845252ac6b662d5c72c29903813eJake Slack public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment) 31003928aee4356845252ac6b662d5c72c29903813eJake Slack { 31103928aee4356845252ac6b662d5c72c29903813eJake Slack WebSocketClient.WebSocketFuture holder = (WebSocketClient.WebSocketFuture)attachment; 31203928aee4356845252ac6b662d5c72c29903813eJake Slack return new HandshakeConnection(endpoint, holder); 31303928aee4356845252ac6b662d5c72c29903813eJake Slack } 31403928aee4356845252ac6b662d5c72c29903813eJake Slack 31503928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 31603928aee4356845252ac6b662d5c72c29903813eJake Slack protected void endPointOpened(SelectChannelEndPoint endpoint) 31703928aee4356845252ac6b662d5c72c29903813eJake Slack { 31803928aee4356845252ac6b662d5c72c29903813eJake Slack // TODO expose on outer class ?? 31903928aee4356845252ac6b662d5c72c29903813eJake Slack } 32003928aee4356845252ac6b662d5c72c29903813eJake Slack 32103928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 32203928aee4356845252ac6b662d5c72c29903813eJake Slack protected void endPointUpgraded(ConnectedEndPoint endpoint, Connection oldConnection) 32303928aee4356845252ac6b662d5c72c29903813eJake Slack { 32403928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.debug("upgrade {} -> {}", oldConnection, endpoint.getConnection()); 32503928aee4356845252ac6b662d5c72c29903813eJake Slack } 32603928aee4356845252ac6b662d5c72c29903813eJake Slack 32703928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 32803928aee4356845252ac6b662d5c72c29903813eJake Slack protected void endPointClosed(SelectChannelEndPoint endpoint) 32903928aee4356845252ac6b662d5c72c29903813eJake Slack { 33003928aee4356845252ac6b662d5c72c29903813eJake Slack endpoint.getConnection().onClose(); 33103928aee4356845252ac6b662d5c72c29903813eJake Slack } 33203928aee4356845252ac6b662d5c72c29903813eJake Slack 33303928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 33403928aee4356845252ac6b662d5c72c29903813eJake Slack protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment) 33503928aee4356845252ac6b662d5c72c29903813eJake Slack { 33603928aee4356845252ac6b662d5c72c29903813eJake Slack if (!(attachment instanceof WebSocketClient.WebSocketFuture)) 33703928aee4356845252ac6b662d5c72c29903813eJake Slack super.connectionFailed(channel, ex, attachment); 33803928aee4356845252ac6b662d5c72c29903813eJake Slack else 33903928aee4356845252ac6b662d5c72c29903813eJake Slack { 34003928aee4356845252ac6b662d5c72c29903813eJake Slack __log.debug(ex); 34103928aee4356845252ac6b662d5c72c29903813eJake Slack WebSocketClient.WebSocketFuture future = (WebSocketClient.WebSocketFuture)attachment; 34203928aee4356845252ac6b662d5c72c29903813eJake Slack 34303928aee4356845252ac6b662d5c72c29903813eJake Slack future.handshakeFailed(ex); 34403928aee4356845252ac6b662d5c72c29903813eJake Slack } 34503928aee4356845252ac6b662d5c72c29903813eJake Slack } 34603928aee4356845252ac6b662d5c72c29903813eJake Slack } 34703928aee4356845252ac6b662d5c72c29903813eJake Slack 34803928aee4356845252ac6b662d5c72c29903813eJake Slack /* ------------------------------------------------------------ */ 34903928aee4356845252ac6b662d5c72c29903813eJake Slack /** 35003928aee4356845252ac6b662d5c72c29903813eJake Slack * Handshake Connection. 35103928aee4356845252ac6b662d5c72c29903813eJake Slack * Handles the connection until the handshake succeeds or fails. 35203928aee4356845252ac6b662d5c72c29903813eJake Slack */ 35303928aee4356845252ac6b662d5c72c29903813eJake Slack class HandshakeConnection extends AbstractConnection implements AsyncConnection 35403928aee4356845252ac6b662d5c72c29903813eJake Slack { 35503928aee4356845252ac6b662d5c72c29903813eJake Slack private final AsyncEndPoint _endp; 35603928aee4356845252ac6b662d5c72c29903813eJake Slack private final WebSocketClient.WebSocketFuture _future; 35703928aee4356845252ac6b662d5c72c29903813eJake Slack private final String _key; 35803928aee4356845252ac6b662d5c72c29903813eJake Slack private final HttpParser _parser; 35903928aee4356845252ac6b662d5c72c29903813eJake Slack private String _accept; 36003928aee4356845252ac6b662d5c72c29903813eJake Slack private String _error; 36103928aee4356845252ac6b662d5c72c29903813eJake Slack private ByteArrayBuffer _handshake; 36203928aee4356845252ac6b662d5c72c29903813eJake Slack 36303928aee4356845252ac6b662d5c72c29903813eJake Slack public HandshakeConnection(AsyncEndPoint endpoint, WebSocketClient.WebSocketFuture future) 36403928aee4356845252ac6b662d5c72c29903813eJake Slack { 36503928aee4356845252ac6b662d5c72c29903813eJake Slack super(endpoint, System.currentTimeMillis()); 36603928aee4356845252ac6b662d5c72c29903813eJake Slack _endp = endpoint; 36703928aee4356845252ac6b662d5c72c29903813eJake Slack _future = future; 36803928aee4356845252ac6b662d5c72c29903813eJake Slack 36903928aee4356845252ac6b662d5c72c29903813eJake Slack byte[] bytes = new byte[16]; 37003928aee4356845252ac6b662d5c72c29903813eJake Slack new Random().nextBytes(bytes); 37103928aee4356845252ac6b662d5c72c29903813eJake Slack _key = new String(B64Code.encode(bytes)); 37203928aee4356845252ac6b662d5c72c29903813eJake Slack 37303928aee4356845252ac6b662d5c72c29903813eJake Slack Buffers buffers = new SimpleBuffers(_buffers.getBuffer(), null); 37403928aee4356845252ac6b662d5c72c29903813eJake Slack _parser = new HttpParser(buffers, _endp, new HttpParser.EventHandler() 37503928aee4356845252ac6b662d5c72c29903813eJake Slack { 37603928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 37703928aee4356845252ac6b662d5c72c29903813eJake Slack public void startResponse(Buffer version, int status, Buffer reason) throws IOException 37803928aee4356845252ac6b662d5c72c29903813eJake Slack { 37903928aee4356845252ac6b662d5c72c29903813eJake Slack if (status != 101) 38003928aee4356845252ac6b662d5c72c29903813eJake Slack { 38103928aee4356845252ac6b662d5c72c29903813eJake Slack _error = "Bad response status " + status + " " + reason; 38203928aee4356845252ac6b662d5c72c29903813eJake Slack _endp.close(); 38303928aee4356845252ac6b662d5c72c29903813eJake Slack } 38403928aee4356845252ac6b662d5c72c29903813eJake Slack } 38503928aee4356845252ac6b662d5c72c29903813eJake Slack 38603928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 38703928aee4356845252ac6b662d5c72c29903813eJake Slack public void parsedHeader(Buffer name, Buffer value) throws IOException 38803928aee4356845252ac6b662d5c72c29903813eJake Slack { 38903928aee4356845252ac6b662d5c72c29903813eJake Slack if (__ACCEPT.equals(name)) 39003928aee4356845252ac6b662d5c72c29903813eJake Slack _accept = value.toString(); 39103928aee4356845252ac6b662d5c72c29903813eJake Slack } 39203928aee4356845252ac6b662d5c72c29903813eJake Slack 39303928aee4356845252ac6b662d5c72c29903813eJake Slack @Override // TODO simone says shouldn't be needed 39403928aee4356845252ac6b662d5c72c29903813eJake Slack public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException 39503928aee4356845252ac6b662d5c72c29903813eJake Slack { 39603928aee4356845252ac6b662d5c72c29903813eJake Slack if (_error == null) 39703928aee4356845252ac6b662d5c72c29903813eJake Slack _error = "Bad response: " + method + " " + url + " " + version; 39803928aee4356845252ac6b662d5c72c29903813eJake Slack _endp.close(); 39903928aee4356845252ac6b662d5c72c29903813eJake Slack } 40003928aee4356845252ac6b662d5c72c29903813eJake Slack 40103928aee4356845252ac6b662d5c72c29903813eJake Slack @Override // TODO simone says shouldn't be needed 40203928aee4356845252ac6b662d5c72c29903813eJake Slack public void content(Buffer ref) throws IOException 40303928aee4356845252ac6b662d5c72c29903813eJake Slack { 40403928aee4356845252ac6b662d5c72c29903813eJake Slack if (_error == null) 40503928aee4356845252ac6b662d5c72c29903813eJake Slack _error = "Bad response. " + ref.length() + "B of content?"; 40603928aee4356845252ac6b662d5c72c29903813eJake Slack _endp.close(); 40703928aee4356845252ac6b662d5c72c29903813eJake Slack } 40803928aee4356845252ac6b662d5c72c29903813eJake Slack }); 40903928aee4356845252ac6b662d5c72c29903813eJake Slack } 41003928aee4356845252ac6b662d5c72c29903813eJake Slack 41103928aee4356845252ac6b662d5c72c29903813eJake Slack private boolean handshake() 41203928aee4356845252ac6b662d5c72c29903813eJake Slack { 41303928aee4356845252ac6b662d5c72c29903813eJake Slack if (_handshake==null) 41403928aee4356845252ac6b662d5c72c29903813eJake Slack { 41503928aee4356845252ac6b662d5c72c29903813eJake Slack String path = _future.getURI().getPath(); 41603928aee4356845252ac6b662d5c72c29903813eJake Slack if (path == null || path.length() == 0) 41703928aee4356845252ac6b662d5c72c29903813eJake Slack path = "/"; 41803928aee4356845252ac6b662d5c72c29903813eJake Slack 41903928aee4356845252ac6b662d5c72c29903813eJake Slack if (_future.getURI().getRawQuery() != null) 42003928aee4356845252ac6b662d5c72c29903813eJake Slack path += "?" + _future.getURI().getRawQuery(); 42103928aee4356845252ac6b662d5c72c29903813eJake Slack 42203928aee4356845252ac6b662d5c72c29903813eJake Slack String origin = _future.getOrigin(); 42303928aee4356845252ac6b662d5c72c29903813eJake Slack 42403928aee4356845252ac6b662d5c72c29903813eJake Slack StringBuilder request = new StringBuilder(512); 42503928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("GET ").append(path).append(" HTTP/1.1\r\n") 42603928aee4356845252ac6b662d5c72c29903813eJake Slack .append("Host: ").append(_future.getURI().getHost()).append(":") 42703928aee4356845252ac6b662d5c72c29903813eJake Slack .append(_future.getURI().getPort()).append("\r\n") 42803928aee4356845252ac6b662d5c72c29903813eJake Slack .append("Upgrade: websocket\r\n") 42903928aee4356845252ac6b662d5c72c29903813eJake Slack .append("Connection: Upgrade\r\n") 43003928aee4356845252ac6b662d5c72c29903813eJake Slack .append("Sec-WebSocket-Key: ") 43103928aee4356845252ac6b662d5c72c29903813eJake Slack .append(_key).append("\r\n"); 43203928aee4356845252ac6b662d5c72c29903813eJake Slack 43303928aee4356845252ac6b662d5c72c29903813eJake Slack if (origin != null) 43403928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("Origin: ").append(origin).append("\r\n"); 43503928aee4356845252ac6b662d5c72c29903813eJake Slack 43603928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("Sec-WebSocket-Version: ").append(WebSocketConnectionRFC6455.VERSION).append("\r\n"); 43703928aee4356845252ac6b662d5c72c29903813eJake Slack 43803928aee4356845252ac6b662d5c72c29903813eJake Slack if (_future.getProtocol() != null) 43903928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("Sec-WebSocket-Protocol: ").append(_future.getProtocol()).append("\r\n"); 44003928aee4356845252ac6b662d5c72c29903813eJake Slack 44103928aee4356845252ac6b662d5c72c29903813eJake Slack Map<String, String> cookies = _future.getCookies(); 44203928aee4356845252ac6b662d5c72c29903813eJake Slack if (cookies != null && cookies.size() > 0) 44303928aee4356845252ac6b662d5c72c29903813eJake Slack { 44403928aee4356845252ac6b662d5c72c29903813eJake Slack for (String cookie : cookies.keySet()) 44503928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("Cookie: ") 44603928aee4356845252ac6b662d5c72c29903813eJake Slack .append(QuotedStringTokenizer.quoteIfNeeded(cookie, HttpFields.__COOKIE_DELIM)) 44703928aee4356845252ac6b662d5c72c29903813eJake Slack .append("=") 44803928aee4356845252ac6b662d5c72c29903813eJake Slack .append(QuotedStringTokenizer.quoteIfNeeded(cookies.get(cookie), HttpFields.__COOKIE_DELIM)) 44903928aee4356845252ac6b662d5c72c29903813eJake Slack .append("\r\n"); 45003928aee4356845252ac6b662d5c72c29903813eJake Slack } 45103928aee4356845252ac6b662d5c72c29903813eJake Slack 45203928aee4356845252ac6b662d5c72c29903813eJake Slack request.append("\r\n"); 45303928aee4356845252ac6b662d5c72c29903813eJake Slack 45403928aee4356845252ac6b662d5c72c29903813eJake Slack _handshake=new ByteArrayBuffer(request.toString(), false); 45503928aee4356845252ac6b662d5c72c29903813eJake Slack } 45603928aee4356845252ac6b662d5c72c29903813eJake Slack 45703928aee4356845252ac6b662d5c72c29903813eJake Slack // TODO extensions 45803928aee4356845252ac6b662d5c72c29903813eJake Slack 45903928aee4356845252ac6b662d5c72c29903813eJake Slack try 46003928aee4356845252ac6b662d5c72c29903813eJake Slack { 46103928aee4356845252ac6b662d5c72c29903813eJake Slack int len = _handshake.length(); 46203928aee4356845252ac6b662d5c72c29903813eJake Slack int flushed = _endp.flush(_handshake); 46303928aee4356845252ac6b662d5c72c29903813eJake Slack if (flushed<0) 46403928aee4356845252ac6b662d5c72c29903813eJake Slack throw new IOException("incomplete handshake"); 46503928aee4356845252ac6b662d5c72c29903813eJake Slack } 46603928aee4356845252ac6b662d5c72c29903813eJake Slack catch (IOException e) 46703928aee4356845252ac6b662d5c72c29903813eJake Slack { 46803928aee4356845252ac6b662d5c72c29903813eJake Slack _future.handshakeFailed(e); 46903928aee4356845252ac6b662d5c72c29903813eJake Slack } 47003928aee4356845252ac6b662d5c72c29903813eJake Slack return _handshake.length()==0; 47103928aee4356845252ac6b662d5c72c29903813eJake Slack } 47203928aee4356845252ac6b662d5c72c29903813eJake Slack 47303928aee4356845252ac6b662d5c72c29903813eJake Slack public Connection handle() throws IOException 47403928aee4356845252ac6b662d5c72c29903813eJake Slack { 47503928aee4356845252ac6b662d5c72c29903813eJake Slack while (_endp.isOpen() && !_parser.isComplete()) 47603928aee4356845252ac6b662d5c72c29903813eJake Slack { 47703928aee4356845252ac6b662d5c72c29903813eJake Slack if (_handshake==null || _handshake.length()>0) 47803928aee4356845252ac6b662d5c72c29903813eJake Slack if (!handshake()) 47903928aee4356845252ac6b662d5c72c29903813eJake Slack return this; 48003928aee4356845252ac6b662d5c72c29903813eJake Slack 48103928aee4356845252ac6b662d5c72c29903813eJake Slack if (!_parser.parseAvailable()) 48203928aee4356845252ac6b662d5c72c29903813eJake Slack { 48303928aee4356845252ac6b662d5c72c29903813eJake Slack if (_endp.isInputShutdown()) 48403928aee4356845252ac6b662d5c72c29903813eJake Slack _future.handshakeFailed(new IOException("Incomplete handshake response")); 48503928aee4356845252ac6b662d5c72c29903813eJake Slack return this; 48603928aee4356845252ac6b662d5c72c29903813eJake Slack } 48703928aee4356845252ac6b662d5c72c29903813eJake Slack } 48803928aee4356845252ac6b662d5c72c29903813eJake Slack if (_error == null) 48903928aee4356845252ac6b662d5c72c29903813eJake Slack { 49003928aee4356845252ac6b662d5c72c29903813eJake Slack if (_accept == null) 49103928aee4356845252ac6b662d5c72c29903813eJake Slack { 49203928aee4356845252ac6b662d5c72c29903813eJake Slack _error = "No Sec-WebSocket-Accept"; 49303928aee4356845252ac6b662d5c72c29903813eJake Slack } 49403928aee4356845252ac6b662d5c72c29903813eJake Slack else if (!WebSocketConnectionRFC6455.hashKey(_key).equals(_accept)) 49503928aee4356845252ac6b662d5c72c29903813eJake Slack { 49603928aee4356845252ac6b662d5c72c29903813eJake Slack _error = "Bad Sec-WebSocket-Accept"; 49703928aee4356845252ac6b662d5c72c29903813eJake Slack } 49803928aee4356845252ac6b662d5c72c29903813eJake Slack else 49903928aee4356845252ac6b662d5c72c29903813eJake Slack { 50003928aee4356845252ac6b662d5c72c29903813eJake Slack WebSocketConnection connection = newWebSocketConnection(); 50103928aee4356845252ac6b662d5c72c29903813eJake Slack 50203928aee4356845252ac6b662d5c72c29903813eJake Slack Buffer header = _parser.getHeaderBuffer(); 50303928aee4356845252ac6b662d5c72c29903813eJake Slack if (header.hasContent()) 50403928aee4356845252ac6b662d5c72c29903813eJake Slack connection.fillBuffersFrom(header); 50503928aee4356845252ac6b662d5c72c29903813eJake Slack _buffers.returnBuffer(header); 50603928aee4356845252ac6b662d5c72c29903813eJake Slack 50703928aee4356845252ac6b662d5c72c29903813eJake Slack _future.onConnection(connection); 50803928aee4356845252ac6b662d5c72c29903813eJake Slack 50903928aee4356845252ac6b662d5c72c29903813eJake Slack return connection; 51003928aee4356845252ac6b662d5c72c29903813eJake Slack } 51103928aee4356845252ac6b662d5c72c29903813eJake Slack } 51203928aee4356845252ac6b662d5c72c29903813eJake Slack 51303928aee4356845252ac6b662d5c72c29903813eJake Slack _endp.close(); 51403928aee4356845252ac6b662d5c72c29903813eJake Slack return this; 51503928aee4356845252ac6b662d5c72c29903813eJake Slack } 51603928aee4356845252ac6b662d5c72c29903813eJake Slack 51703928aee4356845252ac6b662d5c72c29903813eJake Slack private WebSocketConnection newWebSocketConnection() throws IOException 51803928aee4356845252ac6b662d5c72c29903813eJake Slack { 51903928aee4356845252ac6b662d5c72c29903813eJake Slack __log.debug("newWebSocketConnection()"); 52003928aee4356845252ac6b662d5c72c29903813eJake Slack return new WebSocketClientConnection( 52103928aee4356845252ac6b662d5c72c29903813eJake Slack _future._client.getFactory(), 52203928aee4356845252ac6b662d5c72c29903813eJake Slack _future.getWebSocket(), 52303928aee4356845252ac6b662d5c72c29903813eJake Slack _endp, 52403928aee4356845252ac6b662d5c72c29903813eJake Slack _buffers, 52503928aee4356845252ac6b662d5c72c29903813eJake Slack System.currentTimeMillis(), 52603928aee4356845252ac6b662d5c72c29903813eJake Slack _future.getMaxIdleTime(), 52703928aee4356845252ac6b662d5c72c29903813eJake Slack _future.getProtocol(), 52803928aee4356845252ac6b662d5c72c29903813eJake Slack null, 52903928aee4356845252ac6b662d5c72c29903813eJake Slack WebSocketConnectionRFC6455.VERSION, 53003928aee4356845252ac6b662d5c72c29903813eJake Slack _future.getMaskGen()); 53103928aee4356845252ac6b662d5c72c29903813eJake Slack } 53203928aee4356845252ac6b662d5c72c29903813eJake Slack 53303928aee4356845252ac6b662d5c72c29903813eJake Slack public void onInputShutdown() throws IOException 53403928aee4356845252ac6b662d5c72c29903813eJake Slack { 53503928aee4356845252ac6b662d5c72c29903813eJake Slack _endp.close(); 53603928aee4356845252ac6b662d5c72c29903813eJake Slack } 53703928aee4356845252ac6b662d5c72c29903813eJake Slack 53803928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean isIdle() 53903928aee4356845252ac6b662d5c72c29903813eJake Slack { 54003928aee4356845252ac6b662d5c72c29903813eJake Slack return false; 54103928aee4356845252ac6b662d5c72c29903813eJake Slack } 54203928aee4356845252ac6b662d5c72c29903813eJake Slack 54303928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean isSuspended() 54403928aee4356845252ac6b662d5c72c29903813eJake Slack { 54503928aee4356845252ac6b662d5c72c29903813eJake Slack return false; 54603928aee4356845252ac6b662d5c72c29903813eJake Slack } 54703928aee4356845252ac6b662d5c72c29903813eJake Slack 54803928aee4356845252ac6b662d5c72c29903813eJake Slack public void onClose() 54903928aee4356845252ac6b662d5c72c29903813eJake Slack { 55003928aee4356845252ac6b662d5c72c29903813eJake Slack if (_error != null) 55103928aee4356845252ac6b662d5c72c29903813eJake Slack _future.handshakeFailed(new ProtocolException(_error)); 55203928aee4356845252ac6b662d5c72c29903813eJake Slack else 55303928aee4356845252ac6b662d5c72c29903813eJake Slack _future.handshakeFailed(new EOFException()); 55403928aee4356845252ac6b662d5c72c29903813eJake Slack } 55503928aee4356845252ac6b662d5c72c29903813eJake Slack } 55603928aee4356845252ac6b662d5c72c29903813eJake Slack 55703928aee4356845252ac6b662d5c72c29903813eJake Slack private static class WebSocketClientConnection extends WebSocketConnectionRFC6455 55803928aee4356845252ac6b662d5c72c29903813eJake Slack { 55903928aee4356845252ac6b662d5c72c29903813eJake Slack private final WebSocketClientFactory factory; 56003928aee4356845252ac6b662d5c72c29903813eJake Slack 56103928aee4356845252ac6b662d5c72c29903813eJake Slack public WebSocketClientConnection(WebSocketClientFactory factory, WebSocket webSocket, EndPoint endPoint, WebSocketBuffers buffers, long timeStamp, int maxIdleTime, String protocol, List<Extension> extensions, int draftVersion, MaskGen maskGen) throws IOException 56203928aee4356845252ac6b662d5c72c29903813eJake Slack { 56303928aee4356845252ac6b662d5c72c29903813eJake Slack super(webSocket, endPoint, buffers, timeStamp, maxIdleTime, protocol, extensions, draftVersion, maskGen); 56403928aee4356845252ac6b662d5c72c29903813eJake Slack this.factory = factory; 56503928aee4356845252ac6b662d5c72c29903813eJake Slack } 56603928aee4356845252ac6b662d5c72c29903813eJake Slack 56703928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 56803928aee4356845252ac6b662d5c72c29903813eJake Slack public void onClose() 56903928aee4356845252ac6b662d5c72c29903813eJake Slack { 57003928aee4356845252ac6b662d5c72c29903813eJake Slack super.onClose(); 57103928aee4356845252ac6b662d5c72c29903813eJake Slack factory.removeConnection(this); 57203928aee4356845252ac6b662d5c72c29903813eJake Slack } 57303928aee4356845252ac6b662d5c72c29903813eJake Slack } 57403928aee4356845252ac6b662d5c72c29903813eJake Slack} 575