001/* 002 * Copyright (C) 2015-2017 Neo Visionaries Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package NeoVisionaries.WebSockets; 017 018 019import static NeoVisionaries.WebSockets.WebSocketState.CLOSED; 020import static NeoVisionaries.WebSockets.WebSocketState.CLOSING; 021import static NeoVisionaries.WebSockets.WebSocketState.CONNECTING; 022import static NeoVisionaries.WebSockets.WebSocketState.CREATED; 023import static NeoVisionaries.WebSockets.WebSocketState.OPEN; 024 025import java.io.BufferedInputStream; 026import java.io.BufferedOutputStream; 027import java.io.IOException; 028import java.net.Socket; 029import java.net.URI; 030import java.util.List; 031import java.util.Map; 032import java.util.concurrent.Callable; 033import java.util.concurrent.ExecutorService; 034import java.util.concurrent.Future; 035import java.util.concurrent.RejectedExecutionException; 036 037import NeoVisionaries.WebSockets.StateManager.CloseInitiator; 038 039 040/** 041 * WebSocket. 042 * 043 * <EMBED CLASS='external-html' DATA-FILE-ID=LICENSE><BR /> 044 * 045 * <h3>Create WebSocketFactory</h3> 046 * 047 * <p> 048 * {@link WebSocketFactory} is a factory class that creates 049 * {@link WebSocket} instances. The first step is to create a 050 * {@code WebSocketFactory} instance. 051 * </p> 052 * 053 * <blockquote> 054 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a WebSocketFactory instance.</span> 055 * WebSocketFactory factory = new {@link WebSocketFactory#WebSocketFactory() 056 * WebSocketFactory()};</pre> 057 * </blockquote> 058 * 059 * <p> 060 * By default, {@code WebSocketFactory} uses {@link 061 * javax.net.SocketFactory SocketFactory}{@code .}{@link 062 * javax.net.SocketFactory#getDefault() getDefault()} for 063 * non-secure WebSocket connections ({@code ws:}) and {@link 064 * javax.net.ssl.SSLSocketFactory SSLSocketFactory}{@code 065 * .}{@link javax.net.ssl.SSLSocketFactory#getDefault() 066 * getDefault()} for secure WebSocket connections ({@code 067 * wss:}). You can change this default behavior by using 068 * {@code WebSocketFactory.}{@link 069 * WebSocketFactory#setSocketFactory(javax.net.SocketFactory) 070 * setSocketFactory} method, {@code WebSocketFactory.}{@link 071 * WebSocketFactory#setSSLSocketFactory(javax.net.ssl.SSLSocketFactory) 072 * setSSLSocketFactory} method and {@code WebSocketFactory.}{@link 073 * WebSocketFactory#setSSLContext(javax.net.ssl.SSLContext) 074 * setSSLContext} method. Note that you don't have to call a {@code 075 * setSSL*} method at all if you use the default SSL configuration. 076 * Also note that calling {@code setSSLSocketFactory} method has no 077 * meaning if you have called {@code setSSLContext} method. See the 078 * description of {@code WebSocketFactory.}{@link 079 * WebSocketFactory#createSocket(URI) createSocket(URI)} method for 080 * details. 081 * </p> 082 * 083 * <p> 084 * The following is an example to set a custom SSL context to a 085 * {@code WebSocketFactory} instance. (Again, you don't have to call a 086 * {@code setSSL*} method if you use the default SSL configuration.) 087 * </p> 088 * 089 * <blockquote> 090 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a custom SSL context.</span> 091 * SSLContext context = <a href="https://gist.github.com/TakahikoKawasaki/d07de2218b4b81bf65ac" 092 * >NaiveSSLContext</a>.getInstance(<span style="color:darkred;">"TLS"</span>); 093 * 094 * <span style="color: green;">// Set the custom SSL context.</span> 095 * factory.{@link WebSocketFactory#setSSLContext(javax.net.ssl.SSLContext) 096 * setSSLContext}(context); 097 * 098 * <span style="color: green;">// Disable manual hostname verification for NaiveSSLContext. 099 * // 100 * // Manual hostname verification has been enabled since the 101 * // version 2.1. Because the verification is executed manually 102 * // after Socket.connect(SocketAddress, int) succeeds, the 103 * // hostname verification is always executed even if you has 104 * // passed an SSLContext which naively accepts any server 105 * // certificate. However, this behavior is not desirable in 106 * // some cases and you may want to disable the hostname 107 * // verification. You can disable the hostname verification 108 * // by calling WebSocketFactory.setVerifyHostname(false).</span> 109 * factory.{@link WebSocketFactory#setVerifyHostname(boolean) setVerifyHostname}(false);</pre> 110 * </blockquote> 111 * 112 * <p> 113 * <a href="https://gist.github.com/TakahikoKawasaki/d07de2218b4b81bf65ac" 114 * >NaiveSSLContext</a> used in the above example is a factory class to 115 * create an {@link javax.net.ssl.SSLContext SSLContext} which naively 116 * accepts all certificates without verification. It's enough for testing 117 * purposes. When you see an error message 118 * "unable to find valid certificate path to requested target" while 119 * testing, try {@code NaiveSSLContext}. 120 * </p> 121 * 122 * <h3>HTTP Proxy</h3> 123 * 124 * <p> 125 * If a WebSocket endpoint needs to be accessed via an HTTP proxy, 126 * information about the proxy server has to be set to a {@code 127 * WebSocketFactory} instance before creating a {@code WebSocket} 128 * instance. Proxy settings are represented by {@link ProxySettings} 129 * class. A {@code WebSocketFactory} instance has an associated 130 * {@code ProxySettings} instance and it can be obtained by calling 131 * {@code WebSocketFactory.}{@link WebSocketFactory#getProxySettings() 132 * getProxySettings()} method. 133 * </p> 134 * 135 * <blockquote> 136 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Get the associated ProxySettings instance.</span> 137 * {@link ProxySettings} settings = factory.{@link 138 * WebSocketFactory#getProxySettings() getProxySettings()};</pre> 139 * </blockquote> 140 * 141 * <p> 142 * {@code ProxySettings} class has methods to set information about 143 * a proxy server such as {@link ProxySettings#setHost(String) setHost} 144 * method and {@link ProxySettings#setPort(int) setPort} method. The 145 * following is an example to set a secure (<code>https</code>) proxy 146 * server. 147 * </p> 148 * 149 * <blockquote> 150 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Set a proxy server.</span> 151 * settings.{@link ProxySettings#setServer(String) 152 * setServer}(<span style="color:darkred;">"https://proxy.example.com"</span>);</pre> 153 * </blockquote> 154 * 155 * <p> 156 * If credentials are required for authentication at a proxy server, 157 * {@link ProxySettings#setId(String) setId} method and {@link 158 * ProxySettings#setPassword(String) setPassword} method, or 159 * {@link ProxySettings#setCredentials(String, String) setCredentials} 160 * method can be used to set the credentials. Note that, however, 161 * the current implementation supports only Basic Authentication. 162 * </p> 163 * 164 * <blockquote> 165 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Set credentials for authentication at a proxy server.</span> 166 * settings.{@link ProxySettings#setCredentials(String, String) 167 * setCredentials}(id, password); 168 * </pre> 169 * </blockquote> 170 * 171 * <h3>Create WebSocket</h3> 172 * 173 * <p> 174 * {@link WebSocket} class represents a WebSocket. Its instances are 175 * created by calling one of {@code createSocket} methods of a {@link 176 * WebSocketFactory} instance. Below is the simplest example to create 177 * a {@code WebSocket} instance. 178 * </p> 179 * 180 * <blockquote> 181 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a WebSocket. The scheme part can be one of the following: 182 * // 'ws', 'wss', 'http' and 'https' (case-insensitive). The user info 183 * // part, if any, is interpreted as expected. If a raw socket failed 184 * // to be created, an IOException is thrown.</span> 185 * WebSocket ws = new {@link WebSocketFactory#WebSocketFactory() 186 * WebSocketFactory()} 187 * .{@link WebSocketFactory#createSocket(String) 188 * createWebSocket}(<span style="color: darkred;">"ws://localhost/endpoint"</span>);</pre> 189 * </blockquote> 190 * 191 * <p> 192 * There are two ways to set a timeout value for socket connection. The 193 * first way is to call {@link WebSocketFactory#setConnectionTimeout(int) 194 * setConnectionTimeout(int timeout)} method of {@code WebSocketFactory}. 195 * </p> 196 * 197 * <blockquote> 198 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a WebSocket factory and set 5000 milliseconds as a timeout 199 * // value for socket connection.</span> 200 * WebSocketFactory factory = new WebSocketFactory().{@link 201 * WebSocketFactory#setConnectionTimeout(int) setConnectionTimeout}(5000); 202 * 203 * <span style="color: green;">// Create a WebSocket. The timeout value set above is used.</span> 204 * WebSocket ws = factory.{@link WebSocketFactory#createSocket(String) 205 * createWebSocket}(<span style="color: darkred;">"ws://localhost/endpoint"</span>);</pre> 206 * </blockquote> 207 * 208 * <p> 209 * The other way is to give a timeout value to a {@code createSocket} method. 210 * </p> 211 * 212 * <blockquote> 213 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a WebSocket factory. The timeout value remains 0.</span> 214 * WebSocketFactory factory = new WebSocketFactory(); 215 * 216 * <span style="color: green;">// Create a WebSocket with a socket connection timeout value.</span> 217 * WebSocket ws = factory.{@link WebSocketFactory#createSocket(String, int) 218 * createWebSocket}(<span style="color: darkred;">"ws://localhost/endpoint"</span>, 5000);</pre> 219 * </blockquote> 220 * 221 * <p> 222 * The timeout value is passed to {@link Socket#connect(java.net.SocketAddress, int) 223 * connect}{@code (}{@link java.net.SocketAddress SocketAddress}{@code , int)} 224 * method of {@link java.net.Socket}. 225 * </p> 226 * 227 * <h3>Register Listener</h3> 228 * 229 * <p> 230 * After creating a {@code WebSocket} instance, you should call {@link 231 * #addListener(WebSocketListener)} method to register a {@link 232 * WebSocketListener} that receives WebSocket events. {@link 233 * WebSocketAdapter} is an empty implementation of {@link 234 * WebSocketListener} interface. 235 * </p> 236 * 237 * <blockquote> 238 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Register a listener to receive WebSocket events.</span> 239 * ws.{@link #addListener(WebSocketListener) addListener}(new {@link 240 * WebSocketAdapter#WebSocketAdapter() WebSocketAdapter()} { 241 * <span style="color: gray;">{@code @}Override</span> 242 * public void {@link WebSocketListener#onTextMessage(WebSocket, String) 243 * onTextMessage}(WebSocket websocket, String message) throws Exception { 244 * <span style="color: green;">// Received a text message.</span> 245 * ...... 246 * } 247 * });</pre> 248 * </blockquote> 249 * 250 * <p> 251 * The table below is the list of callback methods defined in {@code WebSocketListener} 252 * interface. 253 * </p> 254 * 255 * <blockquote> 256 * <table border="1" cellpadding="5" style="border-collapse: collapse;"> 257 * <caption>{@code WebSocketListener} methods</caption> 258 * <thead> 259 * <tr> 260 * <th>Method</th> 261 * <th>Description</th> 262 * </tr> 263 * </thead> 264 * <tbody> 265 * <tr> 266 * <td>{@link WebSocketListener#handleCallbackError(WebSocket, Throwable) handleCallbackError}</td> 267 * <td>Called when an <code>on<i>Xxx</i>()</code> method threw a {@code Throwable}.</td> 268 * </tr> 269 * <tr> 270 * <td>{@link WebSocketListener#onBinaryFrame(WebSocket, WebSocketFrame) onBinaryFrame}</td> 271 * <td>Called when a binary frame was received.</td> 272 * </tr> 273 * <tr> 274 * <td>{@link WebSocketListener#onBinaryMessage(WebSocket, byte[]) onBinaryMessage}</td> 275 * <td>Called when a binary message was received.</td> 276 * </tr> 277 * <tr> 278 * <td>{@link WebSocketListener#onCloseFrame(WebSocket, WebSocketFrame) onCloseFrame}</td> 279 * <td>Called when a close frame was received.</td> 280 * </tr> 281 * <tr> 282 * <td>{@link WebSocketListener#onConnected(WebSocket, Map) onConnected}</td> 283 * <td>Called after the opening handshake succeeded.</td> 284 * </tr> 285 * <tr> 286 * <td>{@link WebSocketListener#onConnectError(WebSocket, WebSocketException) onConnectError}</td> 287 * <td>Called when {@link #connectAsynchronously()} failed.</td> 288 * </tr> 289 * <tr> 290 * <td>{@link WebSocketListener#onContinuationFrame(WebSocket, WebSocketFrame) onContinuationFrame}</td> 291 * <td>Called when a continuation frame was received.</td> 292 * </tr> 293 * <tr> 294 * <td>{@link WebSocketListener#onDisconnected(WebSocket, WebSocketFrame, WebSocketFrame, boolean) onDisconnected}</td> 295 * <td>Called after a WebSocket connection was closed.</td> 296 * </tr> 297 * <tr> 298 * <td>{@link WebSocketListener#onError(WebSocket, WebSocketException) onError}</td> 299 * <td>Called when an error occurred.</td> 300 * </tr> 301 * <tr> 302 * <td>{@link WebSocketListener#onFrame(WebSocket, WebSocketFrame) onFrame}</td> 303 * <td>Called when a frame was received.</td> 304 * </tr> 305 * <tr> 306 * <td>{@link WebSocketListener#onFrameError(WebSocket, WebSocketException, WebSocketFrame) onFrameError}</td> 307 * <td>Called when a frame failed to be read.</td> 308 * </tr> 309 * <tr> 310 * <td>{@link WebSocketListener#onFrameSent(WebSocket, WebSocketFrame) onFrameSent}</td> 311 * <td>Called when a frame was sent.</td> 312 * </tr> 313 * <tr> 314 * <td>{@link WebSocketListener#onFrameUnsent(WebSocket, WebSocketFrame) onFrameUnsent}</td> 315 * <td>Called when a frame was not sent.</td> 316 * </tr> 317 * <tr> 318 * <td>{@link WebSocketListener#onMessageDecompressionError(WebSocket, WebSocketException, byte[]) onMessageDecompressionError}</td> 319 * <td>Called when a message failed to be decompressed.</td> 320 * </tr> 321 * <tr> 322 * <td>{@link WebSocketListener#onMessageError(WebSocket, WebSocketException, List) onMessageError}</td> 323 * <td>Called when a message failed to be constructed.</td> 324 * </tr> 325 * <tr> 326 * <td>{@link WebSocketListener#onPingFrame(WebSocket, WebSocketFrame) onPingFrame}</td> 327 * <td>Called when a ping frame was received.</td> 328 * </tr> 329 * <tr> 330 * <td>{@link WebSocketListener#onPongFrame(WebSocket, WebSocketFrame) onPongFrame}</td> 331 * <td>Called when a pong frame was received.</td> 332 * </tr> 333 * <tr> 334 * <td>{@link WebSocketListener#onSendError(WebSocket, WebSocketException, WebSocketFrame) onSendError}</td> 335 * <td>Called when an error occurred on sending a frame.</td> 336 * </tr> 337 * <tr> 338 * <td>{@link WebSocketListener#onSendingFrame(WebSocket, WebSocketFrame) onSendingFrame}</td> 339 * <td>Called before a frame is sent.</td> 340 * </tr> 341 * <tr> 342 * <td>{@link WebSocketListener#onSendingHandshake(WebSocket, String, List) onSendingHandshake}</td> 343 * <td>Called before an opening handshake is sent.</td> 344 * </tr> 345 * <tr> 346 * <td>{@link WebSocketListener#onStateChanged(WebSocket, WebSocketState) onStateChanged}</td> 347 * <td>Called when the state of WebSocket changed.</td> 348 * </tr> 349 * <tr> 350 * <td>{@link WebSocketListener#onTextFrame(WebSocket, WebSocketFrame) onTextFrame}</td> 351 * <td>Called when a text frame was received.</td> 352 * </tr> 353 * <tr> 354 * <td>{@link WebSocketListener#onTextMessage(WebSocket, String) onTextMessage}</td> 355 * <td>Called when a text message was received.</td> 356 * </tr> 357 * <tr> 358 * <td>{@link WebSocketListener#onTextMessageError(WebSocket, WebSocketException, byte[]) onTextMessageError}</td> 359 * <td>Called when a text message failed to be constructed.</td> 360 * </tr> 361 * <tr> 362 * <td>{@link WebSocketListener#onThreadCreated(WebSocket, ThreadType, Thread) onThreadCreated}</td> 363 * <td>Called after a thread was created.</td> 364 * </tr> 365 * <tr> 366 * <td>{@link WebSocketListener#onThreadStarted(WebSocket, ThreadType, Thread) onThreadStarted}</td> 367 * <td>Called at the beginning of a thread's {@code run()} method.</td> 368 * </tr> 369 * <tr> 370 * <td>{@link WebSocketListener#onThreadStopping(WebSocket, ThreadType, Thread) onThreadStopping}</td> 371 * <td>Called at the end of a thread's {@code run()} method.</td> 372 * </tr> 373 * <tr> 374 * <td>{@link WebSocketListener#onUnexpectedError(WebSocket, WebSocketException) onUnexpectedError}</td> 375 * <td>Called when an uncaught throwable was detected.</td> 376 * </tr> 377 * </tbody> 378 * </table> 379 * </blockquote> 380 * 381 * <h3>Configure WebSocket</h3> 382 * 383 * <p> 384 * Before starting a WebSocket <a href="https://tools.ietf.org/html/rfc6455#section-4" 385 * >opening handshake</a> with the server, you can configure the 386 * {@code WebSocket} instance by using the following methods. 387 * </p> 388 * 389 * <blockquote> 390 * <table border="1" cellpadding="5" style="border-collapse: collapse;"> 391 * <caption>Methods for Configuration</caption> 392 * <thead> 393 * <tr> 394 * <th>METHOD</th> 395 * <th>DESCRIPTION</th> 396 * </tr> 397 * </thead> 398 * <tbody> 399 * <tr> 400 * <td>{@link #addProtocol(String) addProtocol}</td> 401 * <td>Adds an element to {@code Sec-WebSocket-Protocol}</td> 402 * </tr> 403 * <tr> 404 * <td>{@link #addExtension(WebSocketExtension) addExtension}</td> 405 * <td>Adds an element to {@code Sec-WebSocket-Extensions}</td> 406 * </tr> 407 * <tr> 408 * <td>{@link #addHeader(String, String) addHeader}</td> 409 * <td>Adds an arbitrary HTTP header.</td> 410 * </tr> 411 * <tr> 412 * <td>{@link #setUserInfo(String, String) setUserInfo}</td> 413 * <td>Adds {@code Authorization} header for Basic Authentication.</td> 414 * </tr> 415 * <tr> 416 * <td>{@link #getSocket() getSocket}</td> 417 * <td> 418 * Gets the underlying {@link Socket} instance to configure it. 419 * Note that this may return {@code null} since version 2.9. 420 * Consider using {@link #getConnectedSocket()} as necessary. 421 * </td> 422 * </tr> 423 * <tr> 424 * <td>{@link #getConnectedSocket() getConnectedSocket}</td> 425 * <td> 426 * Establishes and gets the underlying Socket instance to configure it. 427 * Available since version 2.9. 428 * </td> 429 * </tr> 430 * <tr> 431 * <td>{@link #setExtended(boolean) setExtended}</td> 432 * <td>Disables validity checks on RSV1/RSV2/RSV3 and opcode.</td> 433 * </tr> 434 * <tr> 435 * <td>{@link #setFrameQueueSize(int) setFrameQueueSize}</td> 436 * <td>Set the size of the frame queue for <a href="#congestion_control">congestion control</a>.</td> 437 * </tr> 438 * <tr> 439 * <td>{@link #setMaxPayloadSize(int) setMaxPayloadSize}</td> 440 * <td>Set the <a href="#maximum_payload_size">maximum payload size</a>.</td> 441 * </tr> 442 * <tr> 443 * <td>{@link #setMissingCloseFrameAllowed(boolean) setMissingCloseFrameAllowed}</td> 444 * <td>Set whether to allow the server to close the connection without sending a close frame.</td> 445 * </tr> 446 * </tbody> 447 * </table> 448 * </blockquote> 449 * 450 * <h3>Connect To Server</h3> 451 * 452 * <p> 453 * By calling {@link #connect()} method, connection to the server is 454 * established and a WebSocket opening handshake is performed 455 * synchronously. If an error occurred during the handshake, 456 * a {@link WebSocketException} would be thrown. Instead, when the 457 * handshake succeeds, the {@code connect()} implementation creates 458 * threads and starts them to read and write WebSocket frames 459 * asynchronously. 460 * </p> 461 * 462 * <blockquote> 463 * <pre style="border-left: solid 5px lightgray;"> try 464 * { 465 * <span style="color: green;">// Connect to the server and perform an opening handshake.</span> 466 * <span style="color: green;">// This method blocks until the opening handshake is finished.</span> 467 * ws.{@link #connect()}; 468 * } 469 * catch ({@link OpeningHandshakeException} e) 470 * { 471 * <span style="color: green;">// A violation against the WebSocket protocol was detected</span> 472 * <span style="color: green;">// during the opening handshake.</span> 473 * } 474 * catch ({@link HostnameUnverifiedException} e) 475 * { 476 * <span style="color: green;">// The certificate of the peer does not match the expected hostname.</span> 477 * } 478 * catch ({@link WebSocketException} e) 479 * { 480 * <span style="color: green;">// Failed to establish a WebSocket connection.</span> 481 * }</pre> 482 * </blockquote> 483 * 484 * <p> 485 * In some cases, {@code connect()} method throws {@link OpeningHandshakeException} 486 * which is a subclass of {@code WebSocketException} (since version 1.19). 487 * {@code OpeningHandshakeException} provides additional methods such as 488 * {@link OpeningHandshakeException#getStatusLine() getStatusLine()}, 489 * {@link OpeningHandshakeException#getHeaders() getHeaders()} and 490 * {@link OpeningHandshakeException#getBody() getBody()} to access the 491 * response from a server. The following snippet is an example to print 492 * information that the exception holds. 493 * </p> 494 * 495 * <blockquote> 496 * <pre style="border-left: solid 5px lightgray;"> catch ({@link OpeningHandshakeException} e) 497 * { 498 * <span style="color: green;">// Status line.</span> 499 * {@link StatusLine} sl = e.{@link OpeningHandshakeException#getStatusLine() getStatusLine()}; 500 * System.out.println(<span style="color:darkred;">"=== Status Line ==="</span>); 501 * System.out.format(<span style="color:darkred;">"HTTP Version = %s\n"</span>, sl.{@link StatusLine#getHttpVersion() getHttpVersion()}); 502 * System.out.format(<span style="color:darkred;">"Status Code = %d\n"</span>, sl.{@link StatusLine#getStatusCode() getStatusCode()}); 503 * System.out.format(<span style="color:darkred;">"Reason Phrase = %s\n"</span>, sl.{@link StatusLine#getReasonPhrase() getReasonPhrase()}); 504 * 505 * <span style="color: green;">// HTTP headers.</span> 506 * Map<String, List<String>> headers = e.{@link OpeningHandshakeException#getHeaders() getHeaders()}; 507 * System.out.println(<span style="color:darkred;">"=== HTTP Headers ==="</span>); 508 * for (Map.Entry<String, List<String>> entry : headers.entrySet()) 509 * { 510 * <span style="color: green;">// Header name.</span> 511 * String name = entry.getKey(); 512 * 513 * <span style="color: green;">// Values of the header.</span> 514 * List<String> values = entry.getValue(); 515 * 516 * if (values == null || values.size() == 0) 517 * { 518 * <span style="color: green;">// Print the name only.</span> 519 * System.out.println(name); 520 * continue; 521 * } 522 * 523 * for (String value : values) 524 * { 525 * <span style="color: green;">// Print the name and the value.</span> 526 * System.out.format(<span style="color:darkred;">"%s: %s\n"</span>, name, value); 527 * } 528 * } 529 * }</pre> 530 * </blockquote> 531 * 532 * <p> 533 * Also, {@code connect()} method throws {@link HostnameUnverifiedException} 534 * which is a subclass of {@code WebSocketException} (since version 2.1) when 535 * the certificate of the peer does not match the expected hostname. 536 * </p> 537 * 538 * <h3>Connect To Server Asynchronously</h3> 539 * 540 * <p> 541 * The simplest way to call {@code connect()} method asynchronously is to 542 * use {@link #connectAsynchronously()} method. The implementation of the 543 * method creates a thread and calls {@code connect()} method in the thread. 544 * When the {@code connect()} call failed, {@link 545 * WebSocketListener#onConnectError(WebSocket, WebSocketException) 546 * onConnectError()} of {@code WebSocketListener} would be called. Note that 547 * {@code onConnectError()} is called only when {@code connectAsynchronously()} 548 * was used and the {@code connect()} call executed in the background thread 549 * failed. Neither direct synchronous {@code connect()} nor 550 * {@link WebSocket#connect(java.util.concurrent.ExecutorService) 551 * connect(ExecutorService)} (described below) will trigger the callback method. 552 * </p> 553 * 554 * <blockquote> 555 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Connect to the server asynchronously.</span> 556 * ws.{@link #connectAsynchronously()}; 557 * </pre> 558 * </blockquote> 559 * 560 * <p> 561 * Another way to call {@code connect()} method asynchronously is to use 562 * {@link #connect(ExecutorService)} method. The method performs a WebSocket 563 * opening handshake asynchronously using the given {@link ExecutorService}. 564 * </p> 565 * 566 * <blockquote> 567 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Prepare an ExecutorService.</span> 568 * {@link ExecutorService} es = {@link java.util.concurrent.Executors Executors}.{@link 569 * java.util.concurrent.Executors#newSingleThreadExecutor() newSingleThreadExecutor()}; 570 * 571 * <span style="color: green;">// Connect to the server asynchronously.</span> 572 * {@link Future}{@code <WebSocket>} future = ws.{@link #connect(ExecutorService) connect}(es); 573 * 574 * try 575 * { 576 * <span style="color: green;">// Wait for the opening handshake to complete.</span> 577 * future.get(); 578 * } 579 * catch ({@link java.util.concurrent.ExecutionException ExecutionException} e) 580 * { 581 * if (e.getCause() instanceof {@link WebSocketException}) 582 * { 583 * ...... 584 * } 585 * }</pre> 586 * </blockquote> 587 * 588 * <p> 589 * The implementation of {@code connect(ExecutorService)} method creates 590 * a {@link java.util.concurrent.Callable Callable}{@code <WebSocket>} 591 * instance by calling {@link #connectable()} method and passes the 592 * instance to {@link ExecutorService#submit(Callable) submit(Callable)} 593 * method of the given {@code ExecutorService}. What the implementation 594 * of {@link Callable#call() call()} method of the {@code Callable} 595 * instance does is just to call the synchronous {@code connect()}. 596 * </p> 597 * 598 * <h3>Send Frames</h3> 599 * 600 * <p> 601 * WebSocket frames can be sent by {@link #sendFrame(WebSocketFrame)} 602 * method. Other <code>send<i>Xxx</i></code> methods such as {@link 603 * #sendText(String)} are aliases of {@code sendFrame} method. All of 604 * the <code>send<i>Xxx</i></code> methods work asynchronously. 605 * However, under some conditions, <code>send<i>Xxx</i></code> methods 606 * may block. See <a href="#congestion_control">Congestion Control</a> 607 * for details. 608 * </p> 609 * 610 * <p> 611 * Below 612 * are some examples of <code>send<i>Xxx</i></code> methods. Note that 613 * in normal cases, you don't have to call {@link #sendClose()} method 614 * and {@link #sendPong()} (or their variants) explicitly because they 615 * are called automatically when appropriate. 616 * </p> 617 * 618 * <blockquote> 619 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Send a text frame.</span> 620 * ws.{@link #sendText(String) sendText}(<span style="color: darkred;">"Hello."</span>); 621 * 622 * <span style="color: green;">// Send a binary frame.</span> 623 * byte[] binary = ......; 624 * ws.{@link #sendBinary(byte[]) sendBinary}(binary); 625 * 626 * <span style="color: green;">// Send a ping frame.</span> 627 * ws.{@link #sendPing(String) sendPing}(<span style="color: darkred;">"Are you there?"</span>);</pre> 628 * </blockquote> 629 * 630 * <p> 631 * If you want to send fragmented frames, you have to know the details 632 * of the specification (<a href="https://tools.ietf.org/html/rfc6455#section-5.4" 633 * >5.4. Fragmentation</a>). Below is an example to send a text message 634 * ({@code "How are you?"}) which consists of 3 fragmented frames. 635 * </p> 636 * 637 * <blockquote> 638 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// The first frame must be either a text frame or a binary frame. 639 * // And its FIN bit must be cleared.</span> 640 * WebSocketFrame firstFrame = WebSocketFrame 641 * .{@link WebSocketFrame#createTextFrame(String) 642 * createTextFrame}(<span style="color: darkred;">"How "</span>) 643 * .{@link WebSocketFrame#setFin(boolean) setFin}(false); 644 * 645 * <span style="color: green;">// Subsequent frames must be continuation frames. The FIN bit of 646 * // all continuation frames except the last one must be cleared. 647 * // Note that the FIN bit of frames returned from 648 * // WebSocketFrame.createContinuationFrame methods is cleared, so 649 * // the example below does not clear the FIN bit explicitly.</span> 650 * WebSocketFrame secondFrame = WebSocketFrame 651 * .{@link WebSocketFrame#createContinuationFrame(String) 652 * createContinuationFrame}(<span style="color: darkred;">"are "</span>); 653 * 654 * <span style="color: green;">// The last frame must be a continuation frame with the FIN bit set. 655 * // Note that the FIN bit of frames returned from 656 * // WebSocketFrame.createContinuationFrame methods is cleared, so 657 * // the FIN bit of the last frame must be set explicitly.</span> 658 * WebSocketFrame lastFrame = WebSocketFrame 659 * .{@link WebSocketFrame#createContinuationFrame(String) 660 * createContinuationFrame}(<span style="color: darkred;">"you?"</span>) 661 * .{@link WebSocketFrame#setFin(boolean) setFin}(true); 662 * 663 * <span style="color: green;">// Send a text message which consists of 3 frames.</span> 664 * ws.{@link #sendFrame(WebSocketFrame) sendFrame}(firstFrame) 665 * .{@link #sendFrame(WebSocketFrame) sendFrame}(secondFrame) 666 * .{@link #sendFrame(WebSocketFrame) sendFrame}(lastFrame);</pre> 667 * </blockquote> 668 * 669 * <p> 670 * Alternatively, the same as above can be done like this. 671 * </p> 672 * 673 * <blockquote> 674 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Send a text message which consists of 3 frames.</span> 675 * ws.{@link #sendText(String, boolean) sendText}(<span style="color: darkred;">"How "</span>, false) 676 * .{@link #sendContinuation(String) sendContinuation}(<span style="color: darkred;">"are "</span>) 677 * .{@link #sendContinuation(String, boolean) sendContinuation}(<span style="color: darkred;">"you?"</span>, true);</pre> 678 * </blockquote> 679 * 680 * <h3>Send Ping/Pong Frames Periodically</h3> 681 * 682 * <p> 683 * You can send ping frames periodically by calling {@link #setPingInterval(long) 684 * setPingInterval} method with an interval in milliseconds between ping frames. 685 * This method can be called both before and after {@link #connect()} method. 686 * Passing zero stops the periodical sending. 687 * </p> 688 * 689 * <blockquote> 690 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Send a ping per 60 seconds.</span> 691 * ws.{@link #setPingInterval(long) setPingInterval}(60 * 1000); 692 * 693 * <span style="color: green;">// Stop the periodical sending.</span> 694 * ws.{@link #setPingInterval(long) setPingInterval}(0);</pre> 695 * </blockquote> 696 * 697 * <p> 698 * Likewise, you can send pong frames periodically by calling {@link 699 * #setPongInterval(long) setPongInterval} method. "<i>A Pong frame MAY be sent 700 * <b>unsolicited</b>."</i> (<a href="https://tools.ietf.org/html/rfc6455#section-5.5.3" 701 * >RFC 6455, 5.5.3. Pong</a>) 702 * </p> 703 * 704 * <p> 705 * You can customize payload of ping/pong frames that are sent automatically by using 706 * {@link #setPingPayloadGenerator(PayloadGenerator)} and 707 * {@link #setPongPayloadGenerator(PayloadGenerator)} methods. Both methods take an 708 * instance of {@link PayloadGenerator} interface. The following is an example to 709 * use the string representation of the current date as payload of ping frames. 710 * </p> 711 * 712 * <blockquote> 713 * <pre style="border-left: solid 5px lightgray;"> ws.{@link #setPingPayloadGenerator(PayloadGenerator) 714 * setPingPayloadGenerator}(new {@link PayloadGenerator} () { 715 * <span style="color: gray;">{@code @}Override</span> 716 * public byte[] generate() { 717 * <span style="color: green;">// The string representation of the current date.</span> 718 * return new Date().toString().getBytes(); 719 * } 720 * });</pre> 721 * </blockquote> 722 * 723 * <p> 724 * Note that the maximum payload length of control frames (e.g. ping frames) is 125. 725 * Therefore, the length of a byte array returned from {@link PayloadGenerator#generate() 726 * generate()} method must not exceed 125. 727 * </p> 728 * 729 * <p> 730 * You can change the names of the {@link java.util.Timer Timer}s that send ping/pong 731 * frames periodically by using {@link #setPingSenderName(String)} and 732 * {@link #setPongSenderName(String)} methods. 733 * </p> 734 * 735 * <blockquote> 736 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Change the Timers' names.</span> 737 * ws.{@link #setPingSenderName(String) 738 * setPingSenderName}(<span style="color: darkred;">"PING_SENDER"</span>); 739 * ws.{@link #setPongSenderName(String) 740 * setPongSenderName}(<span style="color: darkred;">"PONG_SENDER"</span>); 741 * </pre> 742 * </blockquote> 743 * 744 * <h3>Auto Flush</h3> 745 * 746 * <p> 747 * By default, a frame is automatically flushed to the server immediately after 748 * {@link #sendFrame(WebSocketFrame) sendFrame} method is executed. This automatic 749 * flush can be disabled by calling {@link #setAutoFlush(boolean) setAutoFlush}{@code 750 * (false)}. 751 * </p> 752 * 753 * <blockquote> 754 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Disable auto-flush.</span> 755 * ws.{@link #setAutoFlush(boolean) setAutoFlush}(false);</pre> 756 * </blockquote> 757 * 758 * <p> 759 * To flush frames manually, call {@link #flush()} method. Note that this method 760 * works asynchronously. 761 * </p> 762 * 763 * <blockquote> 764 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Flush frames to the server manually.</span> 765 * ws.{@link #flush()};</pre> 766 * </blockquote> 767 * 768 * <h3 id="congestion_control">Congestion Control</h3> 769 * 770 * <p> 771 * <code>send<i>Xxx</i></code> methods queue a {@link WebSocketFrame} instance to the 772 * internal queue. By default, no upper limit is imposed on the queue size, so 773 * <code>send<i>Xxx</i></code> methods do not block. However, this behavior may cause 774 * a problem if your WebSocket client application sends too many WebSocket frames in 775 * a short time for the WebSocket server to process. In such a case, you may want 776 * <code>send<i>Xxx</i></code> methods to block when many frames are queued. 777 * </p> 778 * 779 * <p> 780 * You can set an upper limit on the internal queue by calling {@link #setFrameQueueSize(int)} 781 * method. As a result, if the number of frames in the queue has reached the upper limit 782 * when a <code>send<i>Xxx</i></code> method is called, the method blocks until the 783 * queue gets spaces. The code snippet below is an example to set 5 as the upper limit 784 * of the internal frame queue. 785 * </p> 786 * 787 * <blockquote> 788 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Set 5 as the frame queue size.</span> 789 * ws.{@link #setFrameQueueSize(int) setFrameQueueSize}(5);</pre> 790 * </blockquote> 791 * 792 * <p> 793 * Note that under some conditions, even if the queue is full, <code>send<i>Xxx</i></code> 794 * methods do not block. For example, in the case where the thread to send frames 795 * ({@code WritingThread}) is going to stop or has already stopped. In addition, 796 * method calls to send a <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 797 * >control frame</a> (e.g. {@link #sendClose()} and {@link #sendPing()}) do not block. 798 * </p> 799 * 800 * <h3 id="maximum_payload_size">Maximum Payload Size</h3> 801 * 802 * <p> 803 * You can set an upper limit on the payload size of WebSocket frames by calling 804 * {@link #setMaxPayloadSize(int)} method with a positive value. Text, binary and 805 * continuation frames whose payload size is bigger than the maximum payload size 806 * you have set will be split into multiple frames. 807 * </p> 808 * 809 * <blockquote> 810 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Set 1024 as the maximum payload size.</span> 811 * ws.{@link #setMaxPayloadSize(int) setMaxPayloadSize}(1024);</pre> 812 * </blockquote> 813 * 814 * <p> 815 * Control frames (close, ping and pong frames) are never split as per the specification. 816 * </p> 817 * 818 * <p> 819 * If permessage-deflate extension is enabled and if the payload size of a WebSocket 820 * frame after compression does not exceed the maximum payload size, the WebSocket 821 * frame is not split even if the payload size before compression execeeds the 822 * maximum payload size. 823 * </p> 824 * 825 * <h3 id="compression">Compression</h3> 826 * 827 * <p> 828 * The <strong>permessage-deflate</strong> extension (<a href= 829 * "http://tools.ietf.org/html/rfc7692">RFC 7692</a>) has been supported 830 * since the version 1.17. To enable the extension, call {@link #addExtension(String) 831 * addExtension} method with {@code "permessage-deflate"}. 832 * </p> 833 * 834 * <blockquote> 835 * <pre style="border-left: solid 5px lightgray;"><span style="color: green;"> // Enable "permessage-deflate" extension (RFC 7692).</span> 836 * ws.{@link #addExtension(String) addExtension}({@link WebSocketExtension#PERMESSAGE_DEFLATE});</pre> 837 * </blockquote> 838 * 839 * <h3>Missing Close Frame</h3> 840 * 841 * <p> 842 * Some server implementations close a WebSocket connection without sending a 843 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> to 844 * a client in some cases. Strictly speaking, this is a violation against the 845 * specification (<a href= 846 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">RFC 6455</a>). However, this 847 * library has allowed the behavior by default since the version 1.29. Even if the 848 * end of the input stream of a WebSocket connection were reached without a close 849 * frame being received, it would trigger neither {@link 850 * WebSocketListener#onError(WebSocket, WebSocketException) onError()} method nor 851 * {@link WebSocketListener#onFrameError(WebSocket, WebSocketException, WebSocketFrame) 852 * onFrameError()} method of {@link WebSocketListener}. If you want to make a 853 * {@code WebSocket} instance report an error in the case, pass {@code false} to 854 * {@link #setMissingCloseFrameAllowed(boolean)} method. 855 * </p> 856 * 857 * <blockquote> 858 * <pre style="border-left: solid 5px lightgray;"><span style="color: green;" 859 * > // Make this library report an error when the end of the input stream 860 * // of the WebSocket connection is reached before a close frame is read.</span> 861 * ws.{@link #setMissingCloseFrameAllowed(boolean) setMissingCloseFrameAllowed}(false);</pre> 862 * </blockquote> 863 * 864 * <h3>Direct Text Message</h3> 865 * 866 * <p> 867 * When a text message was received, {@link WebSocketListener#onTextMessage(WebSocket, String) 868 * onTextMessage(WebSocket, String)} is called. The implementation internally converts 869 * the byte array of the text message into a {@code String} object before calling the 870 * listener method. If you want to receive the byte array directly without the string 871 * conversion, call {@link #setDirectTextMessage(boolean)} with {@code true}, and 872 * {@link WebSocketListener#onTextMessage(WebSocket, byte[]) onTextMessage(WebSocket, byte[])} 873 * will be called instead. 874 * </p> 875 * 876 * <blockquote> 877 * <pre style="border-left: solid 5px lightgray;"><span style="color: green;" 878 * > // Receive text messages without string conversion.</span> 879 * ws.{@link #setDirectTextMessage(boolean) setDirectTextMessage}(true);</pre> 880 * </blockquote> 881 * 882 * <h3>Disconnect WebSocket</h3> 883 * 884 * <p> 885 * Before a WebSocket is closed, a closing handshake is performed. A closing handshake 886 * is started (1) when the server sends a close frame to the client or (2) when the 887 * client sends a close frame to the server. You can start a closing handshake by calling 888 * {@link #disconnect()} method (or by sending a close frame manually). 889 * </p> 890 * 891 * <blockquote> 892 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Close the WebSocket connection.</span> 893 * ws.{@link #disconnect()};</pre> 894 * </blockquote> 895 * 896 * <p> 897 * {@code disconnect()} method has some variants. If you want to change the close code 898 * and the reason phrase of the close frame that this client will send to the server, 899 * use a variant method such as {@link #disconnect(int, String)}. {@code disconnect()} 900 * method itself is an alias of {@code disconnect(}{@link WebSocketCloseCode}{@code 901 * .NORMAL, null)}. 902 * </p> 903 * 904 * <h3>Reconnection</h3> 905 * 906 * <p> 907 * {@code connect()} method can be called at most only once regardless of whether the 908 * method succeeded or failed. If you want to re-connect to the WebSocket endpoint, 909 * you have to create a new {@code WebSocket} instance again by calling one of {@code 910 * createSocket} methods of a {@code WebSocketFactory}. You may find {@link #recreate()} 911 * method useful if you want to create a new {@code WebSocket} instance that has the 912 * same settings as the original instance. Note that, however, settings you made on 913 * the raw socket of the original {@code WebSocket} instance are not copied. 914 * </p> 915 * 916 * <blockquote> 917 * <pre style="border-left: solid 5px lightgray;"> <span style="color: green;">// Create a new WebSocket instance and connect to the same endpoint.</span> 918 * ws = ws.{@link #recreate()}.{@link #connect()};</pre> 919 * </blockquote> 920 * 921 * <p> 922 * There is a variant of {@code recreate()} method that takes a timeout value for 923 * socket connection. If you want to use a timeout value that is different from the 924 * one used when the existing {@code WebSocket} instance was created, use {@link 925 * #recreate(int) recreate(int timeout)} method. 926 * </p> 927 * 928 * <p> 929 * Note that you should not trigger reconnection in {@link 930 * WebSocketListener#onError(WebSocket, WebSocketException) onError()} method 931 * because {@code onError()} may be called multiple times due to one error. Instead, 932 * {@link WebSocketListener#onDisconnected(WebSocket, WebSocketFrame, WebSocketFrame, 933 * boolean) onDisconnected()} is the right place to trigger reconnection. 934 * </p> 935 * 936 * <p> 937 * Also note that the reason I use an expression of <i>"to trigger reconnection"</i> 938 * instead of <i>"to call <code>recreate().connect()</code>"</i> is that I myself 939 * won't do it <i>synchronously</i> in <code>WebSocketListener</code> callback 940 * methods but will just schedule reconnection or will just go to the top of a kind 941 * of <i>application loop</i> that repeats to establish a WebSocket connection until 942 * it succeeds. 943 * </p> 944 * 945 * <h3>Error Handling</h3> 946 * 947 * <p> 948 * {@code WebSocketListener} has some {@code onXxxError()} methods such as {@link 949 * WebSocketListener#onFrameError(WebSocket, WebSocketException, WebSocketFrame) 950 * onFrameError()} and {@link 951 * WebSocketListener#onSendError(WebSocket, WebSocketException, WebSocketFrame) 952 * onSendError()}. Among such methods, {@link 953 * WebSocketListener#onError(WebSocket, WebSocketException) onError()} is a special 954 * one. It is always called before any other {@code onXxxError()} is called. For 955 * example, in the implementation of {@code run()} method of {@code ReadingThread}, 956 * {@code Throwable} is caught and {@code onError()} and {@link 957 * WebSocketListener#onUnexpectedError(WebSocket, WebSocketException) 958 * onUnexpectedError()} are called in this order. The following is the implementation. 959 * </p> 960 * 961 * <blockquote> 962 * <pre style="border-left: solid 5px lightgray;"> <span style="color: gray;">{@code @}Override</span> 963 * public void run() 964 * { 965 * try 966 * { 967 * main(); 968 * } 969 * catch (Throwable t) 970 * { 971 * <span style="color: green;">// An uncaught throwable was detected in the reading thread.</span> 972 * {@link WebSocketException} cause = new WebSocketException( 973 * {@link WebSocketError}.{@link WebSocketError#UNEXPECTED_ERROR_IN_READING_THREAD UNEXPECTED_ERROR_IN_READING_THREAD}, 974 * <span style="color: darkred;">"An uncaught throwable was detected in the reading thread"</span>, t); 975 * 976 * <span style="color: green;">// Notify the listeners.</span> 977 * ListenerManager manager = mWebSocket.getListenerManager(); 978 * manager.callOnError(cause); 979 * manager.callOnUnexpectedError(cause); 980 * } 981 * }</pre> 982 * </blockquote> 983 * 984 * <p> 985 * So, you can handle all error cases in {@code onError()} method. However, note 986 * that {@code onError()} may be called multiple times for one error cause, so don't 987 * try to trigger reconnection in {@code onError()}. Instead, {@link 988 * WebSocketListener#onDisconnected(WebSocket, WebSocketFrame, WebSocketFrame, boolean) 989 * onDiconnected()} is the right place to trigger reconnection. 990 * </p> 991 * 992 * <p> 993 * All {@code onXxxError()} methods receive a {@link WebSocketException} instance 994 * as the second argument (the first argument is a {@code WebSocket} instance). The 995 * exception class provides {@link WebSocketException#getError() getError()} method 996 * which returns a {@link WebSocketError} enum entry. Entries in {@code WebSocketError} 997 * enum are possible causes of errors that may occur in the implementation of this 998 * library. The error causes are so granular that they can make it easy for you to 999 * find the root cause when an error occurs. 1000 * </p> 1001 * 1002 * <p> 1003 * {@code Throwable}s thrown by implementations of {@code onXXX()} callback methods 1004 * are passed to {@link WebSocketListener#handleCallbackError(WebSocket, Throwable) 1005 * handleCallbackError()} of {@code WebSocketListener}. 1006 * </p> 1007 * 1008 * <blockquote> 1009 * <pre style="border-left: solid 5px lightgray;"> <span style="color: gray;">{@code @}Override</span> 1010 * public void {@link WebSocketListener#handleCallbackError(WebSocket, Throwable) 1011 * handleCallbackError}(WebSocket websocket, Throwable cause) throws Exception { 1012 * <span style="color: green;">// Throwables thrown by onXxx() callback methods come here.</span> 1013 * }</pre> 1014 * </blockquote> 1015 * 1016 * <h3>Thread Callbacks</h3> 1017 * 1018 * <p> 1019 * Some threads are created internally in the implementation of {@code WebSocket}. 1020 * Known threads are as follows. 1021 * </p> 1022 * 1023 * <blockquote> 1024 * <table border="1" cellpadding="5" style="border-collapse: collapse;"> 1025 * <caption>Internal Threads</caption> 1026 * <thead> 1027 * <tr> 1028 * <th>THREAD TYPE</th> 1029 * <th>DESCRIPTION</th> 1030 * </tr> 1031 * </thead> 1032 * <tbody> 1033 * <tr> 1034 * <td>{@link ThreadType#READING_THREAD READING_THREAD}</td> 1035 * <td>A thread which reads WebSocket frames from the server.</td> 1036 * </tr> 1037 * <tr> 1038 * <td>{@link ThreadType#WRITING_THREAD WRITING_THREAD}</td> 1039 * <td>A thread which sends WebSocket frames to the server.</td> 1040 * </tr> 1041 * <tr> 1042 * <td>{@link ThreadType#CONNECT_THREAD CONNECT_THREAD}</td> 1043 * <td>A thread which calls {@link WebSocket#connect()} asynchronously.</td> 1044 * </tr> 1045 * <tr> 1046 * <td>{@link ThreadType#FINISH_THREAD FINISH_THREAD}</td> 1047 * <td>A thread which does finalization of a {@code WebSocket} instance.</td> 1048 * </tr> 1049 * </tbody> 1050 * </table> 1051 * </blockquote> 1052 * 1053 * <p> 1054 * The following callback methods of {@link WebSocketListener} are called according 1055 * to the life cycle of the threads. 1056 * </p> 1057 * 1058 * <blockquote> 1059 * <table border="1" cellpadding="5" style="border-collapse: collapse;"> 1060 * <caption>Thread Callbacks</caption> 1061 * <thead> 1062 * <tr> 1063 * <th>METHOD</th> 1064 * <th>DESCRIPTION</th> 1065 * </tr> 1066 * </thead> 1067 * <tbody> 1068 * <tr> 1069 * <td>{@link WebSocketListener#onThreadCreated(WebSocket, ThreadType, Thread) onThreadCreated()}</td> 1070 * <td>Called after a thread was created.</td> 1071 * </tr> 1072 * <tr> 1073 * <td>{@link WebSocketListener#onThreadStarted(WebSocket, ThreadType, Thread) onThreadStarted()}</td> 1074 * <td>Called at the beginning of the thread's {@code run()} method.</td> 1075 * </tr> 1076 * <tr> 1077 * <td>{@link WebSocketListener#onThreadStopping(WebSocket, ThreadType, Thread) onThreadStopping()}</td> 1078 * <td>Called at the end of the thread's {@code run()} method.</td> 1079 * </tr> 1080 * </tbody> 1081 * </table> 1082 * </blockquote> 1083 * 1084 * <p> 1085 * For example, if you want to change the name of the reading thread, 1086 * implement {@link WebSocketListener#onThreadCreated(WebSocket, ThreadType, Thread) 1087 * onThreadCreated()} method like below. 1088 * </p> 1089 * 1090 * <blockquote> 1091 * <pre style="border-left: solid 5px lightgray;"> <span style="color: gray;">{@code @}Override</span> 1092 * public void {@link WebSocketListener#onThreadCreated(WebSocket, ThreadType, Thread) 1093 * onThreadCreated}(WebSocket websocket, {@link ThreadType} type, Thread thread) 1094 * { 1095 * if (type == ThreadType.READING_THREAD) 1096 * { 1097 * thread.setName(<span style="color: darkred;">"READING_THREAD"</span>); 1098 * } 1099 * }</pre> 1100 * </blockquote> 1101 * 1102 * @see <a href="https://tools.ietf.org/html/rfc6455">RFC 6455 (The WebSocket Protocol)</a> 1103 * @see <a href="https://tools.ietf.org/html/rfc7692">RFC 7692 (Compression Extensions for WebSocket)</a> 1104 * @see <a href="https://github.com/TakahikoKawasaki/nv-websocket-client">[GitHub] nv-websocket-client</a> 1105 * 1106 * @author Takahiko Kawasaki 1107 */ 1108public class WebSocket 1109{ 1110 private static final long DEFAULT_CLOSE_DELAY = 10 * 1000L; 1111 private final WebSocketFactory mWebSocketFactory; 1112 private final SocketConnector mSocketConnector; 1113 private final StateManager mStateManager; 1114 private HandshakeBuilder mHandshakeBuilder; 1115 private final ListenerManager mListenerManager; 1116 private final PingSender mPingSender; 1117 private final PongSender mPongSender; 1118 private final Object mThreadsLock = new Object(); 1119 private WebSocketInputStream mInput; 1120 private WebSocketOutputStream mOutput; 1121 private ReadingThread mReadingThread; 1122 private WritingThread mWritingThread; 1123 private Map<String, List<String>> mServerHeaders; 1124 private List<WebSocketExtension> mAgreedExtensions; 1125 private String mAgreedProtocol; 1126 private boolean mExtended; 1127 private boolean mAutoFlush = true; 1128 private boolean mMissingCloseFrameAllowed = true; 1129 private boolean mDirectTextMessage; 1130 private int mFrameQueueSize; 1131 private int mMaxPayloadSize; 1132 private boolean mOnConnectedCalled; 1133 private Object mOnConnectedCalledLock = new Object(); 1134 private boolean mReadingThreadStarted; 1135 private boolean mWritingThreadStarted; 1136 private boolean mReadingThreadFinished; 1137 private boolean mWritingThreadFinished; 1138 private WebSocketFrame mServerCloseFrame; 1139 private WebSocketFrame mClientCloseFrame; 1140 private PerMessageCompressionExtension mPerMessageCompressionExtension; 1141 1142 1143 WebSocket(WebSocketFactory factory, boolean secure, String userInfo, 1144 String host, String path, SocketConnector connector) 1145 { 1146 mWebSocketFactory = factory; 1147 mSocketConnector = connector; 1148 mStateManager = new StateManager(); 1149 mHandshakeBuilder = new HandshakeBuilder(secure, userInfo, host, path); 1150 mListenerManager = new ListenerManager(this); 1151 mPingSender = new PingSender(this, new CounterPayloadGenerator()); 1152 mPongSender = new PongSender(this, new CounterPayloadGenerator()); 1153 } 1154 1155 1156 /** 1157 * Create a new {@code WebSocket} instance that has the same settings 1158 * as this instance. Note that, however, settings you made on the raw 1159 * socket are not copied. 1160 * 1161 * <p> 1162 * The {@link WebSocketFactory} instance that you used to create this 1163 * {@code WebSocket} instance is used again. 1164 * </p> 1165 * 1166 * <p> 1167 * This method calls {@link #recreate(int)} with the timeout value that 1168 * was used when this instance was created. If you want to create a 1169 * socket connection with a different timeout value, use {@link 1170 * #recreate(int)} method instead. 1171 * </p> 1172 * 1173 * @return 1174 * A new {@code WebSocket} instance. 1175 * 1176 * @throws IOException 1177 * {@link WebSocketFactory#createSocket(URI)} threw an exception. 1178 * 1179 * @since 1.6 1180 */ 1181 public WebSocket recreate() throws IOException 1182 { 1183 return recreate(mSocketConnector.getConnectionTimeout()); 1184 } 1185 1186 1187 /** 1188 * Create a new {@code WebSocket} instance that has the same settings 1189 * as this instance. Note that, however, settings you made on the raw 1190 * socket are not copied. 1191 * 1192 * <p> 1193 * The {@link WebSocketFactory} instance that you used to create this 1194 * {@code WebSocket} instance is used again. 1195 * </p> 1196 * 1197 * @return 1198 * A new {@code WebSocket} instance. 1199 * 1200 * @param timeout 1201 * The timeout value in milliseconds for socket timeout. 1202 * A timeout of zero is interpreted as an infinite timeout. 1203 * 1204 * @throws IllegalArgumentException 1205 * The given timeout value is negative. 1206 * 1207 * @throws IOException 1208 * {@link WebSocketFactory#createSocket(URI)} threw an exception. 1209 * 1210 * @since 1.10 1211 */ 1212 public WebSocket recreate(int timeout) throws IOException 1213 { 1214 if (timeout < 0) 1215 { 1216 throw new IllegalArgumentException("The given timeout value is negative."); 1217 } 1218 1219 WebSocket instance = mWebSocketFactory.createSocket(getURI(), timeout); 1220 1221 // Copy the settings. 1222 instance.mHandshakeBuilder = new HandshakeBuilder(mHandshakeBuilder); 1223 instance.setPingInterval(getPingInterval()); 1224 instance.setPongInterval(getPongInterval()); 1225 instance.setPingPayloadGenerator(getPingPayloadGenerator()); 1226 instance.setPongPayloadGenerator(getPongPayloadGenerator()); 1227 instance.mExtended = mExtended; 1228 instance.mAutoFlush = mAutoFlush; 1229 instance.mMissingCloseFrameAllowed = mMissingCloseFrameAllowed; 1230 instance.mDirectTextMessage = mDirectTextMessage; 1231 instance.mFrameQueueSize = mFrameQueueSize; 1232 1233 // Copy listeners. 1234 List<WebSocketListener> listeners = mListenerManager.getListeners(); 1235 synchronized (listeners) 1236 { 1237 instance.addListeners(listeners); 1238 } 1239 1240 return instance; 1241 } 1242 1243 1244 @Override 1245 protected void finalize() throws Throwable 1246 { 1247 if (isInState(CREATED)) 1248 { 1249 // The raw socket needs to be closed. 1250 finish(); 1251 } 1252 1253 super.finalize(); 1254 } 1255 1256 1257 /** 1258 * Get the current state of this WebSocket. 1259 * 1260 * <p> 1261 * The initial state is {@link WebSocketState#CREATED CREATED}. 1262 * When {@link #connect()} is called, the state is changed to 1263 * {@link WebSocketState#CONNECTING CONNECTING}, and then to 1264 * {@link WebSocketState#OPEN OPEN} after a successful opening 1265 * handshake. The state is changed to {@link 1266 * WebSocketState#CLOSING CLOSING} when a closing handshake 1267 * is started, and then to {@link WebSocketState#CLOSED CLOSED} 1268 * when the closing handshake finished. 1269 * </p> 1270 * 1271 * <p> 1272 * See the description of {@link WebSocketState} for details. 1273 * </p> 1274 * 1275 * @return 1276 * The current state. 1277 * 1278 * @see WebSocketState 1279 */ 1280 public WebSocketState getState() 1281 { 1282 synchronized (mStateManager) 1283 { 1284 return mStateManager.getState(); 1285 } 1286 } 1287 1288 1289 /** 1290 * Check if the current state of this WebSocket is {@link 1291 * WebSocketState#OPEN OPEN}. 1292 * 1293 * @return 1294 * {@code true} if the current state is OPEN. 1295 * 1296 * @since 1.1 1297 */ 1298 public boolean isOpen() 1299 { 1300 return isInState(OPEN); 1301 } 1302 1303 1304 /** 1305 * Check if the current state is equal to the specified state. 1306 */ 1307 private boolean isInState(WebSocketState state) 1308 { 1309 synchronized (mStateManager) 1310 { 1311 return (mStateManager.getState() == state); 1312 } 1313 } 1314 1315 1316 /** 1317 * Add a value for {@code Sec-WebSocket-Protocol}. 1318 * 1319 * @param protocol 1320 * A protocol name. 1321 * 1322 * @return 1323 * {@code this} object. 1324 * 1325 * @throws IllegalArgumentException 1326 * The protocol name is invalid. A protocol name must be 1327 * a non-empty string with characters in the range U+0021 1328 * to U+007E not including separator characters. 1329 */ 1330 public WebSocket addProtocol(String protocol) 1331 { 1332 mHandshakeBuilder.addProtocol(protocol); 1333 1334 return this; 1335 } 1336 1337 1338 /** 1339 * Remove a protocol from {@code Sec-WebSocket-Protocol}. 1340 * 1341 * @param protocol 1342 * A protocol name. {@code null} is silently ignored. 1343 * 1344 * @return 1345 * {@code this} object. 1346 * 1347 * @since 1.14 1348 */ 1349 public WebSocket removeProtocol(String protocol) 1350 { 1351 mHandshakeBuilder.removeProtocol(protocol); 1352 1353 return this; 1354 } 1355 1356 1357 /** 1358 * Remove all protocols from {@code Sec-WebSocket-Protocol}. 1359 * 1360 * @return 1361 * {@code this} object. 1362 * 1363 * @since 1.14 1364 */ 1365 public WebSocket clearProtocols() 1366 { 1367 mHandshakeBuilder.clearProtocols(); 1368 1369 return this; 1370 } 1371 1372 1373 /** 1374 * Add a value for {@code Sec-WebSocket-Extension}. 1375 * 1376 * @param extension 1377 * An extension. {@code null} is silently ignored. 1378 * 1379 * @return 1380 * {@code this} object. 1381 */ 1382 public WebSocket addExtension(WebSocketExtension extension) 1383 { 1384 mHandshakeBuilder.addExtension(extension); 1385 1386 return this; 1387 } 1388 1389 1390 /** 1391 * Add a value for {@code Sec-WebSocket-Extension}. The input string 1392 * should comply with the format described in <a href= 1393 * "https://tools.ietf.org/html/rfc6455#section-9.1">9.1. Negotiating 1394 * Extensions</a> in <a href="https://tools.ietf.org/html/rfc6455" 1395 * >RFC 6455</a>. 1396 * 1397 * @param extension 1398 * A string that represents a WebSocket extension. If it does 1399 * not comply with RFC 6455, no value is added to {@code 1400 * Sec-WebSocket-Extension}. 1401 * 1402 * @return 1403 * {@code this} object. 1404 * 1405 * @since 1.14 1406 */ 1407 public WebSocket addExtension(String extension) 1408 { 1409 mHandshakeBuilder.addExtension(extension); 1410 1411 return this; 1412 } 1413 1414 1415 /** 1416 * Remove an extension from {@code Sec-WebSocket-Extension}. 1417 * 1418 * @param extension 1419 * An extension to remove. {@code null} is silently ignored. 1420 * 1421 * @return 1422 * {@code this} object. 1423 * 1424 * @since 1.14 1425 */ 1426 public WebSocket removeExtension(WebSocketExtension extension) 1427 { 1428 mHandshakeBuilder.removeExtension(extension); 1429 1430 return this; 1431 } 1432 1433 1434 /** 1435 * Remove extensions from {@code Sec-WebSocket-Extension} by 1436 * an extension name. 1437 * 1438 * @param name 1439 * An extension name. {@code null} is silently ignored. 1440 * 1441 * @return 1442 * {@code this} object. 1443 * 1444 * @since 1.14 1445 */ 1446 public WebSocket removeExtensions(String name) 1447 { 1448 mHandshakeBuilder.removeExtensions(name); 1449 1450 return this; 1451 } 1452 1453 1454 /** 1455 * Remove all extensions from {@code Sec-WebSocket-Extension}. 1456 * 1457 * @return 1458 * {@code this} object. 1459 * 1460 * @since 1.14 1461 */ 1462 public WebSocket clearExtensions() 1463 { 1464 mHandshakeBuilder.clearExtensions(); 1465 1466 return this; 1467 } 1468 1469 1470 /** 1471 * Add a pair of extra HTTP header. 1472 * 1473 * @param name 1474 * An HTTP header name. When {@code null} or an empty 1475 * string is given, no header is added. 1476 * 1477 * @param value 1478 * The value of the HTTP header. 1479 * 1480 * @return 1481 * {@code this} object. 1482 */ 1483 public WebSocket addHeader(String name, String value) 1484 { 1485 mHandshakeBuilder.addHeader(name, value); 1486 1487 return this; 1488 } 1489 1490 1491 /** 1492 * Remove pairs of extra HTTP headers. 1493 * 1494 * @param name 1495 * An HTTP header name. {@code null} is silently ignored. 1496 * 1497 * @return 1498 * {@code this} object. 1499 * 1500 * @since 1.14 1501 */ 1502 public WebSocket removeHeaders(String name) 1503 { 1504 mHandshakeBuilder.removeHeaders(name); 1505 1506 return this; 1507 } 1508 1509 1510 /** 1511 * Clear all extra HTTP headers. 1512 * 1513 * @return 1514 * {@code this} object. 1515 * 1516 * @since 1.14 1517 */ 1518 public WebSocket clearHeaders() 1519 { 1520 mHandshakeBuilder.clearHeaders(); 1521 1522 return this; 1523 } 1524 1525 1526 /** 1527 * Set the credentials to connect to the WebSocket endpoint. 1528 * 1529 * @param userInfo 1530 * The credentials for Basic Authentication. The format 1531 * should be <code><i>id</i>:<i>password</i></code>. 1532 * 1533 * @return 1534 * {@code this} object. 1535 */ 1536 public WebSocket setUserInfo(String userInfo) 1537 { 1538 mHandshakeBuilder.setUserInfo(userInfo); 1539 1540 return this; 1541 } 1542 1543 1544 /** 1545 * Set the credentials to connect to the WebSocket endpoint. 1546 * 1547 * @param id 1548 * The ID. 1549 * 1550 * @param password 1551 * The password. 1552 * 1553 * @return 1554 * {@code this} object. 1555 */ 1556 public WebSocket setUserInfo(String id, String password) 1557 { 1558 mHandshakeBuilder.setUserInfo(id, password); 1559 1560 return this; 1561 } 1562 1563 1564 /** 1565 * Clear the credentials to connect to the WebSocket endpoint. 1566 * 1567 * @return 1568 * {@code this} object. 1569 * 1570 * @since 1.14 1571 */ 1572 public WebSocket clearUserInfo() 1573 { 1574 mHandshakeBuilder.clearUserInfo(); 1575 1576 return this; 1577 } 1578 1579 1580 /** 1581 * Check if extended use of WebSocket frames are allowed. 1582 * 1583 * <p> 1584 * When extended use is allowed, values of RSV1/RSV2/RSV3 bits 1585 * and opcode of frames are not checked. On the other hand, 1586 * if not allowed (default), non-zero values for RSV1/RSV2/RSV3 1587 * bits and unknown opcodes cause an error. In such a case, 1588 * {@link WebSocketListener#onFrameError(WebSocket, 1589 * WebSocketException, WebSocketFrame) onFrameError} method of 1590 * listeners are called and the WebSocket is eventually closed. 1591 * </p> 1592 * 1593 * @return 1594 * {@code true} if extended use of WebSocket frames 1595 * are allowed. 1596 */ 1597 public boolean isExtended() 1598 { 1599 return mExtended; 1600 } 1601 1602 1603 /** 1604 * Allow or disallow extended use of WebSocket frames. 1605 * 1606 * @param extended 1607 * {@code true} to allow extended use of WebSocket frames. 1608 * 1609 * @return 1610 * {@code this} object. 1611 */ 1612 public WebSocket setExtended(boolean extended) 1613 { 1614 mExtended = extended; 1615 1616 return this; 1617 } 1618 1619 1620 /** 1621 * Check if flush is performed automatically after {@link 1622 * #sendFrame(WebSocketFrame)} is done. The default value is 1623 * {@code true}. 1624 * 1625 * @return 1626 * {@code true} if flush is performed automatically. 1627 * 1628 * @since 1.5 1629 */ 1630 public boolean isAutoFlush() 1631 { 1632 return mAutoFlush; 1633 } 1634 1635 1636 /** 1637 * Enable or disable auto-flush of sent frames. 1638 * 1639 * @param auto 1640 * {@code true} to enable auto-flush. {@code false} to 1641 * disable it. 1642 * 1643 * @return 1644 * {@code this} object. 1645 * 1646 * @since 1.5 1647 */ 1648 public WebSocket setAutoFlush(boolean auto) 1649 { 1650 mAutoFlush = auto; 1651 1652 return this; 1653 } 1654 1655 1656 /** 1657 * Check if this instance allows the server to close the WebSocket 1658 * connection without sending a <a href= 1659 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 1660 * to this client. The default value is {@code true}. 1661 * 1662 * @return 1663 * {@code true} if the configuration allows for the server to 1664 * close the WebSocket connection without sending a close frame 1665 * to this client. {@code false} if the configuration requires 1666 * that an error be reported via 1667 * {@link WebSocketListener#onError(WebSocket, WebSocketException) 1668 * onError()} method and {@link WebSocketListener#onFrameError(WebSocket, 1669 * WebSocketException, WebSocketFrame) onFrameError()} method of 1670 * {@link WebSocketListener}. 1671 * 1672 * @since 1.29 1673 */ 1674 public boolean isMissingCloseFrameAllowed() 1675 { 1676 return mMissingCloseFrameAllowed; 1677 } 1678 1679 1680 /** 1681 * Set whether to allow the server to close the WebSocket connection 1682 * without sending a <a href= 1683 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 1684 * to this client. 1685 * 1686 * @param allowed 1687 * {@code true} to allow the server to close the WebSocket 1688 * connection without sending a close frame to this client. 1689 * {@code false} to make this instance report an error when the 1690 * end of the input stream of the WebSocket connection is reached 1691 * before a close frame is read. 1692 * 1693 * @return 1694 * {@code this} object. 1695 * 1696 * @since 1.29 1697 */ 1698 public WebSocket setMissingCloseFrameAllowed(boolean allowed) 1699 { 1700 mMissingCloseFrameAllowed = allowed; 1701 1702 return this; 1703 } 1704 1705 1706 /** 1707 * Check if text messages are passed to listeners without string conversion. 1708 * 1709 * <p> 1710 * If this method returns {@code true}, when a text message is received, 1711 * {@link WebSocketListener#onTextMessage(WebSocket, byte[]) 1712 * onTextMessage(WebSocket, byte[])} will be called instead of 1713 * {@link WebSocketListener#onTextMessage(WebSocket, String) 1714 * onTextMessage(WebSocket, String)}. The purpose of this behavior 1715 * is to skip internal string conversion which is performed in the 1716 * implementation of {@code ReadingThread}. 1717 * </p> 1718 * 1719 * @return 1720 * {@code true} if text messages are passed to listeners without 1721 * string conversion. 1722 * 1723 * @since 2.6 1724 */ 1725 public boolean isDirectTextMessage() 1726 { 1727 return mDirectTextMessage; 1728 } 1729 1730 1731 /** 1732 * Set whether to receive text messages directly as byte arrays without 1733 * string conversion. 1734 * 1735 * <p> 1736 * If {@code true} is set to this property, when a text message is received, 1737 * {@link WebSocketListener#onTextMessage(WebSocket, byte[]) 1738 * onTextMessage(WebSocket, byte[])} will be called instead of 1739 * {@link WebSocketListener#onTextMessage(WebSocket, String) 1740 * onTextMessage(WebSocket, String)}. The purpose of this behavior 1741 * is to skip internal string conversion which is performed in the 1742 * implementation of {@code ReadingThread}. 1743 * </p> 1744 * 1745 * @param direct 1746 * {@code true} to receive text messages as byte arrays. 1747 * 1748 * @return 1749 * {@code this} object. 1750 * 1751 * @since 2.6 1752 */ 1753 public WebSocket setDirectTextMessage(boolean direct) 1754 { 1755 mDirectTextMessage = direct; 1756 1757 return this; 1758 } 1759 1760 1761 /** 1762 * Flush frames to the server. Flush is performed asynchronously. 1763 * 1764 * @return 1765 * {@code this} object. 1766 * 1767 * @since 1.5 1768 */ 1769 public WebSocket flush() 1770 { 1771 synchronized (mStateManager) 1772 { 1773 WebSocketState state = mStateManager.getState(); 1774 1775 if (state != OPEN && state != CLOSING) 1776 { 1777 return this; 1778 } 1779 } 1780 1781 // Get the reference to the instance of WritingThread. 1782 WritingThread wt = mWritingThread; 1783 1784 // If and only if an instance of WritingThread is available. 1785 if (wt != null) 1786 { 1787 // Request flush. 1788 wt.queueFlush(); 1789 } 1790 1791 return this; 1792 } 1793 1794 1795 /** 1796 * Get the size of the frame queue. The default value is 0 and it means 1797 * there is no limit on the queue size. 1798 * 1799 * @return 1800 * The size of the frame queue. 1801 * 1802 * @since 1.15 1803 */ 1804 public int getFrameQueueSize() 1805 { 1806 return mFrameQueueSize; 1807 } 1808 1809 1810 /** 1811 * Set the size of the frame queue. The default value is 0 and it means 1812 * there is no limit on the queue size. 1813 * 1814 * <p> 1815 * <code>send<i>Xxx</i></code> methods queue a {@link WebSocketFrame} 1816 * instance to the internal queue. If the number of frames in the queue 1817 * has reached the upper limit (which has been set by this method) when 1818 * a <code>send<i>Xxx</i></code> method is called, the method blocks 1819 * until the queue gets spaces. 1820 * </p> 1821 * 1822 * <p> 1823 * Under some conditions, even if the queue is full, <code>send<i>Xxx</i></code> 1824 * methods do not block. For example, in the case where the thread to send 1825 * frames ({@code WritingThread}) is going to stop or has already stopped. 1826 * In addition, method calls to send a <a href= 1827 * "https://tools.ietf.org/html/rfc6455#section-5.5">control frame</a> (e.g. 1828 * {@link #sendClose()} and {@link #sendPing()}) do not block. 1829 * </p> 1830 * 1831 * @param size 1832 * The queue size. 0 means no limit. Negative numbers are not allowed. 1833 * 1834 * @return 1835 * {@code this} object. 1836 * 1837 * @throws IllegalArgumentException 1838 * {@code size} is negative. 1839 * 1840 * @since 1.15 1841 */ 1842 public WebSocket setFrameQueueSize(int size) throws IllegalArgumentException 1843 { 1844 if (size < 0) 1845 { 1846 throw new IllegalArgumentException("size must not be negative."); 1847 } 1848 1849 mFrameQueueSize = size; 1850 1851 return this; 1852 } 1853 1854 1855 /** 1856 * Get the maximum payload size. The default value is 0 which means that 1857 * the maximum payload size is not set and as a result frames are not split. 1858 * 1859 * @return 1860 * The maximum payload size. 0 means that the maximum payload size 1861 * is not set. 1862 * 1863 * @since 1.27 1864 */ 1865 public int getMaxPayloadSize() 1866 { 1867 return mMaxPayloadSize; 1868 } 1869 1870 1871 /** 1872 * Set the maximum payload size. 1873 * 1874 * <p> 1875 * Text, binary and continuation frames whose payload size is bigger than 1876 * the maximum payload size will be split into multiple frames. Note that 1877 * control frames (close, ping and pong frames) are not split as per the 1878 * specification even if their payload size exceeds the maximum payload size. 1879 * </p> 1880 * 1881 * @param size 1882 * The maximum payload size. 0 to unset the maximum payload size. 1883 * 1884 * @return 1885 * {@code this} object. 1886 * 1887 * @throws IllegalArgumentException 1888 * {@code size} is negative. 1889 * 1890 * @since 1.27 1891 */ 1892 public WebSocket setMaxPayloadSize(int size) throws IllegalArgumentException 1893 { 1894 if (size < 0) 1895 { 1896 throw new IllegalArgumentException("size must not be negative."); 1897 } 1898 1899 mMaxPayloadSize = size; 1900 1901 return this; 1902 } 1903 1904 1905 /** 1906 * Get the interval of periodical 1907 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">ping</a> 1908 * frames. 1909 * 1910 * @return 1911 * The interval in milliseconds. 1912 * 1913 * @since 1.2 1914 */ 1915 public long getPingInterval() 1916 { 1917 return mPingSender.getInterval(); 1918 } 1919 1920 1921 /** 1922 * Set the interval of periodical 1923 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">ping</a> 1924 * frames. 1925 * 1926 * <p> 1927 * Setting a positive number starts sending ping frames periodically. 1928 * Setting zero stops the periodical sending. This method can be called 1929 * both before and after {@link #connect()} method. 1930 * </p> 1931 * 1932 * @param interval 1933 * The interval in milliseconds. A negative value is 1934 * regarded as zero. 1935 * 1936 * @return 1937 * {@code this} object. 1938 * 1939 * @since 1.2 1940 */ 1941 public WebSocket setPingInterval(long interval) 1942 { 1943 mPingSender.setInterval(interval); 1944 1945 return this; 1946 } 1947 1948 1949 /** 1950 * Get the interval of periodical 1951 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pong</a> 1952 * frames. 1953 * 1954 * @return 1955 * The interval in milliseconds. 1956 * 1957 * @since 1.2 1958 */ 1959 public long getPongInterval() 1960 { 1961 return mPongSender.getInterval(); 1962 } 1963 1964 1965 /** 1966 * Set the interval of periodical 1967 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pong</a> 1968 * frames. 1969 * 1970 * <p> 1971 * Setting a positive number starts sending pong frames periodically. 1972 * Setting zero stops the periodical sending. This method can be called 1973 * both before and after {@link #connect()} method. 1974 * </p> 1975 * 1976 * <blockquote> 1977 * <dl> 1978 * <dt> 1979 * <span style="font-weight: normal;">An excerpt from <a href= 1980 * "https://tools.ietf.org/html/rfc6455#section-5.5.3" 1981 * >RFC 6455, 5.5.3. Pong</a></span> 1982 * </dt> 1983 * <dd> 1984 * <p><i> 1985 * A Pong frame MAY be sent <b>unsolicited</b>. This serves as a 1986 * unidirectional heartbeat. A response to an unsolicited Pong 1987 * frame is not expected. 1988 * </i></p> 1989 * </dd> 1990 * </dl> 1991 * </blockquote> 1992 * 1993 * @param interval 1994 * The interval in milliseconds. A negative value is 1995 * regarded as zero. 1996 * 1997 * @return 1998 * {@code this} object. 1999 * 2000 * @since 1.2 2001 */ 2002 public WebSocket setPongInterval(long interval) 2003 { 2004 mPongSender.setInterval(interval); 2005 2006 return this; 2007 } 2008 2009 2010 /** 2011 * Get the generator of payload of ping frames that are sent automatically. 2012 * 2013 * @return 2014 * The generator of payload ping frames that are sent automatically. 2015 * 2016 * @since 1.20 2017 */ 2018 public PayloadGenerator getPingPayloadGenerator() 2019 { 2020 return mPingSender.getPayloadGenerator(); 2021 } 2022 2023 2024 /** 2025 * Set the generator of payload of ping frames that are sent automatically. 2026 * 2027 * @param generator 2028 * The generator of payload ping frames that are sent automatically. 2029 * 2030 * @since 1.20 2031 */ 2032 public WebSocket setPingPayloadGenerator(PayloadGenerator generator) 2033 { 2034 mPingSender.setPayloadGenerator(generator); 2035 2036 return this; 2037 } 2038 2039 2040 /** 2041 * Get the generator of payload of pong frames that are sent automatically. 2042 * 2043 * @return 2044 * The generator of payload pong frames that are sent automatically. 2045 * 2046 * @since 1.20 2047 */ 2048 public PayloadGenerator getPongPayloadGenerator() 2049 { 2050 return mPongSender.getPayloadGenerator(); 2051 } 2052 2053 2054 /** 2055 * Set the generator of payload of pong frames that are sent automatically. 2056 * 2057 * @param generator 2058 * The generator of payload ppng frames that are sent automatically. 2059 * 2060 * @since 1.20 2061 */ 2062 public WebSocket setPongPayloadGenerator(PayloadGenerator generator) 2063 { 2064 mPongSender.setPayloadGenerator(generator); 2065 2066 return this; 2067 } 2068 2069 2070 /** 2071 * Get the name of the {@code Timer} that sends ping frames periodically. 2072 * 2073 * @return 2074 * The {@code Timer}'s name. 2075 * 2076 * @since 2.5 2077 */ 2078 public String getPingSenderName() 2079 { 2080 return mPingSender.getTimerName(); 2081 } 2082 2083 2084 /** 2085 * Set the name of the {@code Timer} that sends ping frames periodically. 2086 * 2087 * @param name 2088 * A name for the {@code Timer}. 2089 * 2090 * @return 2091 * {@code this} object. 2092 * 2093 * @since 2.5 2094 */ 2095 public WebSocket setPingSenderName(String name) 2096 { 2097 mPingSender.setTimerName(name); 2098 2099 return this; 2100 } 2101 2102 2103 /** 2104 * Get the name of the {@code Timer} that sends pong frames periodically. 2105 * 2106 * @return 2107 * The {@code Timer}'s name. 2108 * 2109 * @since 2.5 2110 */ 2111 public String getPongSenderName() 2112 { 2113 return mPongSender.getTimerName(); 2114 } 2115 2116 2117 /** 2118 * Set the name of the {@code Timer} that sends pong frames periodically. 2119 * 2120 * @param name 2121 * A name for the {@code Timer}. 2122 * 2123 * @return 2124 * {@code this} object. 2125 * 2126 * @since 2.5 2127 */ 2128 public WebSocket setPongSenderName(String name) 2129 { 2130 mPongSender.setTimerName(name); 2131 2132 return this; 2133 } 2134 2135 2136 /** 2137 * Add a listener to receive events on this WebSocket. 2138 * 2139 * @param listener 2140 * A listener to add. 2141 * 2142 * @return 2143 * {@code this} object. 2144 */ 2145 public WebSocket addListener(WebSocketListener listener) 2146 { 2147 mListenerManager.addListener(listener); 2148 2149 return this; 2150 } 2151 2152 2153 /** 2154 * Add listeners. 2155 * 2156 * @param listeners 2157 * Listeners to add. {@code null} is silently ignored. 2158 * {@code null} elements in the list are ignored, too. 2159 * 2160 * @return 2161 * {@code this} object. 2162 * 2163 * @since 1.14 2164 */ 2165 public WebSocket addListeners(List<WebSocketListener> listeners) 2166 { 2167 mListenerManager.addListeners(listeners); 2168 2169 return this; 2170 } 2171 2172 2173 /** 2174 * Remove a listener from this WebSocket. 2175 * 2176 * @param listener 2177 * A listener to remove. {@code null} won't cause an error. 2178 * 2179 * @return 2180 * {@code this} object. 2181 * 2182 * @since 1.13 2183 */ 2184 public WebSocket removeListener(WebSocketListener listener) 2185 { 2186 mListenerManager.removeListener(listener); 2187 2188 return this; 2189 } 2190 2191 2192 /** 2193 * Remove listeners. 2194 * 2195 * @param listeners 2196 * Listeners to remove. {@code null} is silently ignored. 2197 * {@code null} elements in the list are ignored, too. 2198 * 2199 * @return 2200 * {@code this} object. 2201 * 2202 * @since 1.14 2203 */ 2204 public WebSocket removeListeners(List<WebSocketListener> listeners) 2205 { 2206 mListenerManager.removeListeners(listeners); 2207 2208 return this; 2209 } 2210 2211 2212 /** 2213 * Remove all the listeners from this WebSocket. 2214 * 2215 * @return 2216 * {@code this} object. 2217 * 2218 * @since 1.13 2219 */ 2220 public WebSocket clearListeners() 2221 { 2222 mListenerManager.clearListeners(); 2223 2224 return this; 2225 } 2226 2227 2228 /** 2229 * Get the raw socket which this WebSocket uses internally if it has been 2230 * established, yet. 2231 * 2232 * <p> 2233 * Version 2.9 has changed the behavior of this method, and this method may 2234 * return {@code null} if the underlying socket has not been established yet. 2235 * Consider using {@link #getConnectedSocket()} method as necessary. 2236 * </p> 2237 * 2238 * @return 2239 * The underlying {@link Socket} instance. 2240 * This may be {@code null} in case the underlying socket has not 2241 * been established, yet. 2242 * 2243 * @see #getConnectedSocket() 2244 */ 2245 public Socket getSocket() 2246 { 2247 return mSocketConnector.getSocket(); 2248 } 2249 2250 2251 /** 2252 * Get the raw socket which this WebSocket uses internally. This will 2253 * establish a connection to the server if not already done. 2254 * 2255 * @return 2256 * The underlying {@link Socket} instance. 2257 * 2258 * @since 2.9 2259 */ 2260 public Socket getConnectedSocket() throws WebSocketException 2261 { 2262 return mSocketConnector.getConnectedSocket(); 2263 } 2264 2265 2266 /** 2267 * Get the URI of the WebSocket endpoint. The scheme part is either 2268 * {@code "ws"} or {@code "wss"}. The authority part is always empty. 2269 * 2270 * @return 2271 * The URI of the WebSocket endpoint. 2272 * 2273 * @since 1.1 2274 */ 2275 public URI getURI() 2276 { 2277 return mHandshakeBuilder.getURI(); 2278 } 2279 2280 2281 /** 2282 * Connect to the server, send an opening handshake to the server, 2283 * receive the response and then start threads to communicate with 2284 * the server. 2285 * 2286 * <p> 2287 * As necessary, {@link #addProtocol(String)}, {@link #addExtension(WebSocketExtension)} 2288 * {@link #addHeader(String, String)} should be called before you call this 2289 * method. It is because the parameters set by these methods are used in the 2290 * opening handshake. 2291 * </p> 2292 * 2293 * <p> 2294 * Also, as necessary, {@link #getSocket()} should be used to set up socket 2295 * parameters before you call this method. For example, you can set the 2296 * socket timeout like the following. Note that, however, because the version 2297 * 2.9 changed the behavior of {@link #getSocket()} and the method may return 2298 * {@code null} if the underlying socket has not been established yet, you may 2299 * need to use {@link #getConnectedSocket()} method instead. 2300 * </p> 2301 * 2302 * <pre> 2303 * WebSocket websocket = ......; 2304 * websocket.{@link #getSocket() getSocket()}.{@link Socket#setSoTimeout(int) 2305 * setSoTimeout}(5000); 2306 * 2307 * <span style="color: green;">// getConnectedSocket() instead of getSocket(), since version 2.9.</span> 2308 * websocket.{@link #getConnectedSocket() getConnectedSocket()}.{@link 2309 * Socket#setSoTimeout(int) setSoTimeout}(5000); 2310 * </pre> 2311 * 2312 * <p> 2313 * If the WebSocket endpoint requires Basic Authentication, you can set 2314 * credentials by {@link #setUserInfo(String) setUserInfo(userInfo)} or 2315 * {@link #setUserInfo(String, String) setUserInfo(id, password)} before 2316 * you call this method. 2317 * Note that if the URI passed to {@link WebSocketFactory}{@code 2318 * .createSocket} method contains the user-info part, you don't have to 2319 * call {@code setUserInfo} method. 2320 * </p> 2321 * 2322 * <p> 2323 * Note that this method can be called at most only once regardless of 2324 * whether this method succeeded or failed. If you want to re-connect to 2325 * the WebSocket endpoint, you have to create a new {@code WebSocket} 2326 * instance again by calling one of {@code createSocket} methods of a 2327 * {@link WebSocketFactory}. You may find {@link #recreate()} method 2328 * useful if you want to create a new {@code WebSocket} instance that 2329 * has the same settings as this instance. (But settings you made on 2330 * the raw socket are not copied.) 2331 * </p> 2332 * 2333 * @return 2334 * {@code this} object. 2335 * 2336 * @throws WebSocketException 2337 * <ul> 2338 * <li>The current state of the WebSocket is not {@link 2339 * WebSocketState#CREATED CREATED} 2340 * </li> 2341 * <li>Connecting the server failed.</li> 2342 * <li>The opening handshake failed.</li> 2343 * </ul> 2344 */ 2345 public WebSocket connect() throws WebSocketException 2346 { 2347 // Change the state to CONNECTING. If the state before 2348 // the change is not CREATED, an exception is thrown. 2349 changeStateOnConnect(); 2350 2351 // HTTP headers from the server. 2352 Map<String, List<String>> headers; 2353 2354 try 2355 { 2356 // Connect to the server. 2357 Socket socket = mSocketConnector.connect(); 2358 2359 // Perform WebSocket handshake. 2360 headers = shakeHands(socket); 2361 } 2362 catch (WebSocketException e) 2363 { 2364 // Close the socket. 2365 mSocketConnector.closeSilently(); 2366 2367 // Change the state to CLOSED. 2368 mStateManager.setState(CLOSED); 2369 2370 // Notify the listener of the state change. 2371 mListenerManager.callOnStateChanged(CLOSED); 2372 2373 // The handshake failed. 2374 throw e; 2375 } 2376 2377 // HTTP headers in the response from the server. 2378 mServerHeaders = headers; 2379 2380 // Extensions. 2381 mPerMessageCompressionExtension = findAgreedPerMessageCompressionExtension(); 2382 2383 // Change the state to OPEN. 2384 mStateManager.setState(OPEN); 2385 2386 // Notify the listener of the state change. 2387 mListenerManager.callOnStateChanged(OPEN); 2388 2389 // Start threads that communicate with the server. 2390 startThreads(); 2391 2392 return this; 2393 } 2394 2395 2396 /** 2397 * Execute {@link #connect()} asynchronously using the given {@link 2398 * ExecutorService}. This method is just an alias of the following. 2399 * 2400 * <blockquote> 2401 * <code>executorService.{@link ExecutorService#submit(Callable) submit}({@link #connectable()})</code> 2402 * </blockquote> 2403 * 2404 * @param executorService 2405 * An {@link ExecutorService} to execute a task created by 2406 * {@link #connectable()}. 2407 * 2408 * @return 2409 * The value returned from {@link ExecutorService#submit(Callable)}. 2410 * 2411 * @throws NullPointerException 2412 * If the given {@link ExecutorService} is {@code null}. 2413 * 2414 * @throws RejectedExecutionException 2415 * If the given {@link ExecutorService} rejected the task 2416 * created by {@link #connectable()}. 2417 * 2418 * @see #connectAsynchronously() 2419 * 2420 * @since 1.7 2421 */ 2422 public Future<WebSocket> connect(ExecutorService executorService) 2423 { 2424 return executorService.submit(connectable()); 2425 } 2426 2427 2428 /** 2429 * Get a new {@link Callable}{@code <}{@link WebSocket}{@code >} instance 2430 * whose {@link Callable#call() call()} method calls {@link #connect()} 2431 * method of this {@code WebSocket} instance. 2432 * 2433 * @return 2434 * A new {@link Callable}{@code <}{@link WebSocket}{@code >} instance 2435 * for asynchronous {@link #connect()}. 2436 * 2437 * @see #connect(ExecutorService) 2438 * 2439 * @since 1.7 2440 */ 2441 public Callable<WebSocket> connectable() 2442 { 2443 return new Connectable(this); 2444 } 2445 2446 2447 /** 2448 * Execute {@link #connect()} asynchronously by creating a new thread and 2449 * calling {@code connect()} in the thread. If {@code connect()} failed, 2450 * {@link WebSocketListener#onConnectError(WebSocket, WebSocketException) 2451 * onConnectError()} method of {@link WebSocketListener} is called. 2452 * 2453 * @return 2454 * {@code this} object. 2455 * 2456 * @since 1.8 2457 */ 2458 public WebSocket connectAsynchronously() 2459 { 2460 Thread thread = new ConnectThread(this); 2461 2462 // Get the reference (just in case) 2463 ListenerManager lm = mListenerManager; 2464 2465 if (lm != null) 2466 { 2467 lm.callOnThreadCreated(ThreadType.CONNECT_THREAD, thread); 2468 } 2469 2470 thread.start(); 2471 2472 return this; 2473 } 2474 2475 2476 /** 2477 * Disconnect the WebSocket. 2478 * 2479 * <p> 2480 * This method is an alias of {@link #disconnect(int, String) 2481 * disconnect}{@code (}{@link WebSocketCloseCode#NORMAL}{@code , null)}. 2482 * </p> 2483 * 2484 * @return 2485 * {@code this} object. 2486 */ 2487 public WebSocket disconnect() 2488 { 2489 return disconnect(WebSocketCloseCode.NORMAL, null); 2490 } 2491 2492 2493 /** 2494 * Disconnect the WebSocket. 2495 * 2496 * <p> 2497 * This method is an alias of {@link #disconnect(int, String) 2498 * disconnect}{@code (closeCode, null)}. 2499 * </p> 2500 * 2501 * @param closeCode 2502 * The close code embedded in a <a href= 2503 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2504 * which this WebSocket client will send to the server. 2505 * 2506 * @return 2507 * {@code this} object. 2508 * 2509 * @since 1.5 2510 */ 2511 public WebSocket disconnect(int closeCode) 2512 { 2513 return disconnect(closeCode, null); 2514 } 2515 2516 2517 /** 2518 * Disconnect the WebSocket. 2519 * 2520 * <p> 2521 * This method is an alias of {@link #disconnect(int, String) 2522 * disconnect}{@code (}{@link WebSocketCloseCode#NORMAL}{@code , reason)}. 2523 * </p> 2524 * 2525 * @param reason 2526 * The reason embedded in a <a href= 2527 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2528 * which this WebSocket client will send to the server. Note that 2529 * the length of the bytes which represents the given reason must 2530 * not exceed 125. In other words, {@code (reason.}{@link 2531 * String#getBytes(String) getBytes}{@code ("UTF-8").length <= 125)} 2532 * must be true. 2533 * 2534 * @return 2535 * {@code this} object. 2536 * 2537 * @since 1.5 2538 */ 2539 public WebSocket disconnect(String reason) 2540 { 2541 return disconnect(WebSocketCloseCode.NORMAL, reason); 2542 } 2543 2544 2545 /** 2546 * Disconnect the WebSocket. 2547 * 2548 * <p> 2549 * This method is an alias of {@link #disconnect(int, String, long) 2550 * disconnect}{@code (closeCode, reason, 10000L)}. 2551 * </p> 2552 * 2553 * @param closeCode 2554 * The close code embedded in a <a href= 2555 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2556 * which this WebSocket client will send to the server. 2557 * 2558 * @param reason 2559 * The reason embedded in a <a href= 2560 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2561 * which this WebSocket client will send to the server. Note that 2562 * the length of the bytes which represents the given reason must 2563 * not exceed 125. In other words, {@code (reason.}{@link 2564 * String#getBytes(String) getBytes}{@code ("UTF-8").length <= 125)} 2565 * must be true. 2566 * 2567 * @return 2568 * {@code this} object. 2569 * 2570 * @see WebSocketCloseCode 2571 * 2572 * @see <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">RFC 6455, 5.5.1. Close</a> 2573 * 2574 * @since 1.5 2575 */ 2576 public WebSocket disconnect(int closeCode, String reason) 2577 { 2578 return disconnect(closeCode, reason, DEFAULT_CLOSE_DELAY); 2579 } 2580 2581 2582 /** 2583 * Disconnect the WebSocket. 2584 * 2585 * @param closeCode 2586 * The close code embedded in a <a href= 2587 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2588 * which this WebSocket client will send to the server. 2589 * 2590 * @param reason 2591 * The reason embedded in a <a href= 2592 * "https://tools.ietf.org/html/rfc6455#section-5.5.1">close frame</a> 2593 * which this WebSocket client will send to the server. Note that 2594 * the length of the bytes which represents the given reason must 2595 * not exceed 125. In other words, {@code (reason.}{@link 2596 * String#getBytes(String) getBytes}{@code ("UTF-8").length <= 125)} 2597 * must be true. 2598 * 2599 * @param closeDelay 2600 * Delay in milliseconds before calling {@link Socket#close()} forcibly. 2601 * This safeguard is needed for the case where the server fails to send 2602 * back a close frame. The default value is 10000 (= 10 seconds). When 2603 * a negative value is given, the default value is used. 2604 * 2605 * If a very short time (e.g. 0) is given, it is likely to happen either 2606 * (1) that this client will fail to send a close frame to the server 2607 * (in this case, you will probably see an error message "Flushing frames 2608 * to the server failed: Socket closed") or (2) that the WebSocket 2609 * connection will be closed before this client receives a close frame 2610 * from the server (in this case, the second argument of {@link 2611 * WebSocketListener#onDisconnected(WebSocket, WebSocketFrame, 2612 * WebSocketFrame, boolean) WebSocketListener.onDisconnected} will be 2613 * {@code null}). 2614 * 2615 * @return 2616 * {@code this} object. 2617 * 2618 * @see WebSocketCloseCode 2619 * 2620 * @see <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">RFC 6455, 5.5.1. Close</a> 2621 * 2622 * @since 1.26 2623 */ 2624 public WebSocket disconnect(int closeCode, String reason, long closeDelay) 2625 { 2626 synchronized (mStateManager) 2627 { 2628 switch (mStateManager.getState()) 2629 { 2630 case CREATED: 2631 finishAsynchronously(); 2632 return this; 2633 2634 case OPEN: 2635 break; 2636 2637 default: 2638 // - CONNECTING 2639 // It won't happen unless the programmer dare call 2640 // open() and disconnect() in parallel. 2641 // 2642 // - CLOSING 2643 // A closing handshake has already been started. 2644 // 2645 // - CLOSED 2646 // The connection has already been closed. 2647 return this; 2648 } 2649 2650 // Change the state to CLOSING. 2651 mStateManager.changeToClosing(CloseInitiator.CLIENT); 2652 2653 // Create a close frame. 2654 WebSocketFrame frame = WebSocketFrame.createCloseFrame(closeCode, reason); 2655 2656 // Send the close frame to the server. 2657 sendFrame(frame); 2658 } 2659 2660 // Notify the listeners of the state change. 2661 mListenerManager.callOnStateChanged(CLOSING); 2662 2663 // If a negative value is given. 2664 if (closeDelay < 0) 2665 { 2666 // Use the default value. 2667 closeDelay = DEFAULT_CLOSE_DELAY; 2668 } 2669 2670 // Request the threads to stop. 2671 stopThreads(closeDelay); 2672 2673 return this; 2674 } 2675 2676 2677 /** 2678 * Get the agreed extensions. 2679 * 2680 * <p> 2681 * This method works correctly only after {@link #connect()} succeeds 2682 * (= after the opening handshake succeeds). 2683 * </p> 2684 * 2685 * @return 2686 * The agreed extensions. 2687 */ 2688 public List<WebSocketExtension> getAgreedExtensions() 2689 { 2690 return mAgreedExtensions; 2691 } 2692 2693 2694 /** 2695 * Get the agreed protocol. 2696 * 2697 * <p> 2698 * This method works correctly only after {@link #connect()} succeeds 2699 * (= after the opening handshake succeeds). 2700 * </p> 2701 * 2702 * @return 2703 * The agreed protocol. 2704 */ 2705 public String getAgreedProtocol() 2706 { 2707 return mAgreedProtocol; 2708 } 2709 2710 2711 /** 2712 * Send a WebSocket frame to the server. 2713 * 2714 * <p> 2715 * This method just queues the given frame. Actual transmission 2716 * is performed asynchronously. 2717 * </p> 2718 * 2719 * <p> 2720 * When the current state of this WebSocket is not {@link 2721 * WebSocketState#OPEN OPEN}, this method does not accept 2722 * the frame. 2723 * </p> 2724 * 2725 * <p> 2726 * Sending a <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1" 2727 * >close frame</a> changes the state to {@link WebSocketState#CLOSING 2728 * CLOSING} (if the current state is neither {@link WebSocketState#CLOSING 2729 * CLOSING} nor {@link WebSocketState#CLOSED CLOSED}). 2730 * </p> 2731 * 2732 * <p> 2733 * Note that the validity of the give frame is not checked. 2734 * For example, even if the payload length of a given frame 2735 * is greater than 125 and the opcode indicates that the 2736 * frame is a control frame, this method accepts the given 2737 * frame. 2738 * </p> 2739 * 2740 * @param frame 2741 * A WebSocket frame to be sent to the server. 2742 * If {@code null} is given, nothing is done. 2743 * 2744 * @return 2745 * {@code this} object. 2746 */ 2747 public WebSocket sendFrame(WebSocketFrame frame) 2748 { 2749 if (frame == null) 2750 { 2751 return this; 2752 } 2753 2754 synchronized (mStateManager) 2755 { 2756 WebSocketState state = mStateManager.getState(); 2757 2758 if (state != OPEN && state != CLOSING) 2759 { 2760 return this; 2761 } 2762 } 2763 2764 // The current state is either OPEN or CLOSING. Or, CLOSED. 2765 2766 // Get the reference to the writing thread. 2767 WritingThread wt = mWritingThread; 2768 2769 // Some applications call sendFrame() without waiting for the 2770 // notification of WebSocketListener.onConnected() (Issue #23), 2771 // and/or even after the connection is closed. That is, there 2772 // are chances that sendFrame() is called when mWritingThread 2773 // is null. So, it should be checked whether an instance of 2774 // WritingThread is available or not before calling queueFrame(). 2775 if (wt == null) 2776 { 2777 // An instance of WritingThread is not available. 2778 return this; 2779 } 2780 2781 // Split the frame into multiple frames if necessary. 2782 List<WebSocketFrame> frames = splitIfNecessary(frame); 2783 2784 // Queue the frame or the frames. Even if the current state is 2785 // CLOSED, queueing won't be a big issue. 2786 2787 // If the frame was not split. 2788 if (frames == null) 2789 { 2790 // Queue the frame. 2791 wt.queueFrame(frame); 2792 } 2793 else 2794 { 2795 for (WebSocketFrame f : frames) 2796 { 2797 // Queue the frame. 2798 wt.queueFrame(f); 2799 } 2800 } 2801 2802 return this; 2803 } 2804 2805 2806 private List<WebSocketFrame> splitIfNecessary(WebSocketFrame frame) 2807 { 2808 return WebSocketFrame.splitIfNecessary(frame, mMaxPayloadSize, mPerMessageCompressionExtension); 2809 } 2810 2811 2812 /** 2813 * Send a continuation frame to the server. 2814 * 2815 * <p> 2816 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2817 * sendFrame}{@code (WebSocketFrame.}{@link 2818 * WebSocketFrame#createContinuationFrame() 2819 * createContinuationFrame()}{@code )}. 2820 * </p> 2821 * 2822 * <p> 2823 * Note that the FIN bit of a frame sent by this method is {@code false}. 2824 * If you want to set the FIN bit, use {@link #sendContinuation(boolean) 2825 * sendContinuation(boolean fin)} with {@code fin=true}. 2826 * </p> 2827 * 2828 * @return 2829 * {@code this} object. 2830 */ 2831 public WebSocket sendContinuation() 2832 { 2833 return sendFrame(WebSocketFrame.createContinuationFrame()); 2834 } 2835 2836 2837 /** 2838 * Send a continuation frame to the server. 2839 * 2840 * <p> 2841 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2842 * sendFrame}{@code (WebSocketFrame.}{@link 2843 * WebSocketFrame#createContinuationFrame() 2844 * createContinuationFrame()}{@code .}{@link 2845 * WebSocketFrame#setFin(boolean) setFin}{@code (fin))}. 2846 * </p> 2847 * 2848 * @param fin 2849 * The FIN bit value. 2850 * 2851 * @return 2852 * {@code this} object. 2853 */ 2854 public WebSocket sendContinuation(boolean fin) 2855 { 2856 return sendFrame(WebSocketFrame.createContinuationFrame().setFin(fin)); 2857 } 2858 2859 2860 /** 2861 * Send a continuation frame to the server. 2862 * 2863 * <p> 2864 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2865 * sendFrame}{@code (WebSocketFrame.}{@link 2866 * WebSocketFrame#createContinuationFrame(String) 2867 * createContinuationFrame}{@code (payload))}. 2868 * </p> 2869 * 2870 * <p> 2871 * Note that the FIN bit of a frame sent by this method is {@code false}. 2872 * If you want to set the FIN bit, use {@link #sendContinuation(String, 2873 * boolean) sendContinuation(String payload, boolean fin)} with {@code 2874 * fin=true}. 2875 * </p> 2876 * 2877 * @param payload 2878 * The payload of a continuation frame. 2879 * 2880 * @return 2881 * {@code this} object. 2882 */ 2883 public WebSocket sendContinuation(String payload) 2884 { 2885 return sendFrame(WebSocketFrame.createContinuationFrame(payload)); 2886 } 2887 2888 2889 /** 2890 * Send a continuation frame to the server. 2891 * 2892 * <p> 2893 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2894 * sendFrame}{@code (WebSocketFrame.}{@link 2895 * WebSocketFrame#createContinuationFrame(String) 2896 * createContinuationFrame}{@code (payload).}{@link 2897 * WebSocketFrame#setFin(boolean) setFin}{@code (fin))}. 2898 * </p> 2899 * 2900 * @param payload 2901 * The payload of a continuation frame. 2902 * 2903 * @param fin 2904 * The FIN bit value. 2905 * 2906 * @return 2907 * {@code this} object. 2908 */ 2909 public WebSocket sendContinuation(String payload, boolean fin) 2910 { 2911 return sendFrame(WebSocketFrame.createContinuationFrame(payload).setFin(fin)); 2912 } 2913 2914 2915 /** 2916 * Send a continuation frame to the server. 2917 * 2918 * <p> 2919 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2920 * sendFrame}{@code (WebSocketFrame.}{@link 2921 * WebSocketFrame#createContinuationFrame(byte[]) 2922 * createContinuationFrame}{@code (payload))}. 2923 * </p> 2924 * 2925 * <p> 2926 * Note that the FIN bit of a frame sent by this method is {@code false}. 2927 * If you want to set the FIN bit, use {@link #sendContinuation(byte[], 2928 * boolean) sendContinuation(byte[] payload, boolean fin)} with {@code 2929 * fin=true}. 2930 * </p> 2931 * 2932 * @param payload 2933 * The payload of a continuation frame. 2934 * 2935 * @return 2936 * {@code this} object. 2937 */ 2938 public WebSocket sendContinuation(byte[] payload) 2939 { 2940 return sendFrame(WebSocketFrame.createContinuationFrame(payload)); 2941 } 2942 2943 2944 /** 2945 * Send a continuation frame to the server. 2946 * 2947 * <p> 2948 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2949 * sendFrame}{@code (WebSocketFrame.}{@link 2950 * WebSocketFrame#createContinuationFrame(byte[]) 2951 * createContinuationFrame}{@code (payload).}{@link 2952 * WebSocketFrame#setFin(boolean) setFin}{@code (fin))}. 2953 * </p> 2954 * 2955 * @param payload 2956 * The payload of a continuation frame. 2957 * 2958 * @param fin 2959 * The FIN bit value. 2960 * 2961 * @return 2962 * {@code this} object. 2963 */ 2964 public WebSocket sendContinuation(byte[] payload, boolean fin) 2965 { 2966 return sendFrame(WebSocketFrame.createContinuationFrame(payload).setFin(fin)); 2967 } 2968 2969 2970 /** 2971 * Send a text message to the server. 2972 * 2973 * <p> 2974 * This method is an alias of {@link #sendFrame(WebSocketFrame) 2975 * sendFrame}{@code (WebSocketFrame.}{@link 2976 * WebSocketFrame#createTextFrame(String) 2977 * createTextFrame}{@code (message))}. 2978 * </p> 2979 * 2980 * <p> 2981 * If you want to send a text frame that is to be followed by 2982 * continuation frames, use {@link #sendText(String, boolean) 2983 * setText(String payload, boolean fin)} with {@code fin=false}. 2984 * </p> 2985 * 2986 * @param message 2987 * A text message to be sent to the server. 2988 * 2989 * @return 2990 * {@code this} object. 2991 */ 2992 public WebSocket sendText(String message) 2993 { 2994 return sendFrame(WebSocketFrame.createTextFrame(message)); 2995 } 2996 2997 2998 /** 2999 * Send a text frame to the server. 3000 * 3001 * <p> 3002 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3003 * sendFrame}{@code (WebSocketFrame.}{@link 3004 * WebSocketFrame#createTextFrame(String) 3005 * createTextFrame}{@code (payload).}{@link 3006 * WebSocketFrame#setFin(boolean) setFin}{@code (fin))}. 3007 * </p> 3008 * 3009 * @param payload 3010 * The payload of a text frame. 3011 * 3012 * @param fin 3013 * The FIN bit value. 3014 * 3015 * @return 3016 * {@code this} object. 3017 */ 3018 public WebSocket sendText(String payload, boolean fin) 3019 { 3020 return sendFrame(WebSocketFrame.createTextFrame(payload).setFin(fin)); 3021 } 3022 3023 3024 /** 3025 * Send a binary message to the server. 3026 * 3027 * <p> 3028 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3029 * sendFrame}{@code (WebSocketFrame.}{@link 3030 * WebSocketFrame#createBinaryFrame(byte[]) 3031 * createBinaryFrame}{@code (message))}. 3032 * </p> 3033 * 3034 * <p> 3035 * If you want to send a binary frame that is to be followed by 3036 * continuation frames, use {@link #sendBinary(byte[], boolean) 3037 * setBinary(byte[] payload, boolean fin)} with {@code fin=false}. 3038 * </p> 3039 * 3040 * @param message 3041 * A binary message to be sent to the server. 3042 * 3043 * @return 3044 * {@code this} object. 3045 */ 3046 public WebSocket sendBinary(byte[] message) 3047 { 3048 return sendFrame(WebSocketFrame.createBinaryFrame(message)); 3049 } 3050 3051 3052 /** 3053 * Send a binary frame to the server. 3054 * 3055 * <p> 3056 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3057 * sendFrame}{@code (WebSocketFrame.}{@link 3058 * WebSocketFrame#createBinaryFrame(byte[]) 3059 * createBinaryFrame}{@code (payload).}{@link 3060 * WebSocketFrame#setFin(boolean) setFin}{@code (fin))}. 3061 * </p> 3062 * 3063 * @param payload 3064 * The payload of a binary frame. 3065 * 3066 * @param fin 3067 * The FIN bit value. 3068 * 3069 * @return 3070 * {@code this} object. 3071 */ 3072 public WebSocket sendBinary(byte[] payload, boolean fin) 3073 { 3074 return sendFrame(WebSocketFrame.createBinaryFrame(payload).setFin(fin)); 3075 } 3076 3077 3078 /** 3079 * Send a close frame to the server. 3080 * 3081 * <p> 3082 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3083 * sendFrame}{@code (WebSocketFrame.}{@link 3084 * WebSocketFrame#createCloseFrame() createCloseFrame()}). 3085 * </p> 3086 * 3087 * @return 3088 * {@code this} object. 3089 */ 3090 public WebSocket sendClose() 3091 { 3092 return sendFrame(WebSocketFrame.createCloseFrame()); 3093 } 3094 3095 3096 /** 3097 * Send a close frame to the server. 3098 * 3099 * <p> 3100 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3101 * sendFrame}{@code (WebSocketFrame.}{@link 3102 * WebSocketFrame#createCloseFrame(int) 3103 * createCloseFrame}{@code (closeCode))}. 3104 * </p> 3105 * 3106 * @param closeCode 3107 * The close code. 3108 * 3109 * @return 3110 * {@code this} object. 3111 * 3112 * @see WebSocketCloseCode 3113 */ 3114 public WebSocket sendClose(int closeCode) 3115 { 3116 return sendFrame(WebSocketFrame.createCloseFrame(closeCode)); 3117 } 3118 3119 3120 /** 3121 * Send a close frame to the server. 3122 * 3123 * <p> 3124 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3125 * sendFrame}{@code (WebSocketFrame.}{@link 3126 * WebSocketFrame#createCloseFrame(int, String) 3127 * createCloseFrame}{@code (closeCode, reason))}. 3128 * </p> 3129 * 3130 * @param closeCode 3131 * The close code. 3132 * 3133 * @param reason 3134 * The close reason. 3135 * Note that a control frame's payload length must be 125 bytes or less 3136 * (RFC 6455, <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 3137 * >5.5. Control Frames</a>). 3138 * 3139 * @return 3140 * {@code this} object. 3141 * 3142 * @see WebSocketCloseCode 3143 */ 3144 public WebSocket sendClose(int closeCode, String reason) 3145 { 3146 return sendFrame(WebSocketFrame.createCloseFrame(closeCode, reason)); 3147 } 3148 3149 3150 /** 3151 * Send a ping frame to the server. 3152 * 3153 * <p> 3154 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3155 * sendFrame}{@code (WebSocketFrame.}{@link 3156 * WebSocketFrame#createPingFrame() createPingFrame()}). 3157 * </p> 3158 * 3159 * @return 3160 * {@code this} object. 3161 */ 3162 public WebSocket sendPing() 3163 { 3164 return sendFrame(WebSocketFrame.createPingFrame()); 3165 } 3166 3167 3168 /** 3169 * Send a ping frame to the server. 3170 * 3171 * <p> 3172 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3173 * sendFrame}{@code (WebSocketFrame.}{@link 3174 * WebSocketFrame#createPingFrame(byte[]) 3175 * createPingFrame}{@code (payload))}. 3176 * </p> 3177 * 3178 * @param payload 3179 * The payload for a ping frame. 3180 * Note that a control frame's payload length must be 125 bytes or less 3181 * (RFC 6455, <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 3182 * >5.5. Control Frames</a>). 3183 * 3184 * @return 3185 * {@code this} object. 3186 */ 3187 public WebSocket sendPing(byte[] payload) 3188 { 3189 return sendFrame(WebSocketFrame.createPingFrame(payload)); 3190 } 3191 3192 3193 /** 3194 * Send a ping frame to the server. 3195 * 3196 * <p> 3197 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3198 * sendFrame}{@code (WebSocketFrame.}{@link 3199 * WebSocketFrame#createPingFrame(String) 3200 * createPingFrame}{@code (payload))}. 3201 * </p> 3202 * 3203 * @param payload 3204 * The payload for a ping frame. 3205 * Note that a control frame's payload length must be 125 bytes or less 3206 * (RFC 6455, <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 3207 * >5.5. Control Frames</a>). 3208 * 3209 * @return 3210 * {@code this} object. 3211 */ 3212 public WebSocket sendPing(String payload) 3213 { 3214 return sendFrame(WebSocketFrame.createPingFrame(payload)); 3215 } 3216 3217 3218 /** 3219 * Send a pong frame to the server. 3220 * 3221 * <p> 3222 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3223 * sendFrame}{@code (WebSocketFrame.}{@link 3224 * WebSocketFrame#createPongFrame() createPongFrame()}). 3225 * </p> 3226 * 3227 * @return 3228 * {@code this} object. 3229 */ 3230 public WebSocket sendPong() 3231 { 3232 return sendFrame(WebSocketFrame.createPongFrame()); 3233 } 3234 3235 3236 /** 3237 * Send a pong frame to the server. 3238 * 3239 * <p> 3240 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3241 * sendFrame}{@code (WebSocketFrame.}{@link 3242 * WebSocketFrame#createPongFrame(byte[]) 3243 * createPongFrame}{@code (payload))}. 3244 * </p> 3245 * 3246 * @param payload 3247 * The payload for a pong frame. 3248 * Note that a control frame's payload length must be 125 bytes or less 3249 * (RFC 6455, <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 3250 * >5.5. Control Frames</a>). 3251 * 3252 * @return 3253 * {@code this} object. 3254 */ 3255 public WebSocket sendPong(byte[] payload) 3256 { 3257 return sendFrame(WebSocketFrame.createPongFrame(payload)); 3258 } 3259 3260 3261 /** 3262 * Send a pong frame to the server. 3263 * 3264 * <p> 3265 * This method is an alias of {@link #sendFrame(WebSocketFrame) 3266 * sendFrame}{@code (WebSocketFrame.}{@link 3267 * WebSocketFrame#createPongFrame(String) 3268 * createPongFrame}{@code (payload))}. 3269 * </p> 3270 * 3271 * @param payload 3272 * The payload for a pong frame. 3273 * Note that a control frame's payload length must be 125 bytes or less 3274 * (RFC 6455, <a href="https://tools.ietf.org/html/rfc6455#section-5.5" 3275 * >5.5. Control Frames</a>). 3276 * 3277 * @return 3278 * {@code this} object. 3279 */ 3280 public WebSocket sendPong(String payload) 3281 { 3282 return sendFrame(WebSocketFrame.createPongFrame(payload)); 3283 } 3284 3285 3286 private void changeStateOnConnect() throws WebSocketException 3287 { 3288 synchronized (mStateManager) 3289 { 3290 // If the current state is not CREATED. 3291 if (mStateManager.getState() != CREATED) 3292 { 3293 throw new WebSocketException( 3294 WebSocketError.NOT_IN_CREATED_STATE, 3295 "The current state of the WebSocket is not CREATED."); 3296 } 3297 3298 // Change the state to CONNECTING. 3299 mStateManager.setState(CONNECTING); 3300 } 3301 3302 // Notify the listeners of the state change. 3303 mListenerManager.callOnStateChanged(CONNECTING); 3304 } 3305 3306 3307 /** 3308 * Perform the opening handshake. 3309 */ 3310 private Map<String, List<String>> shakeHands(Socket socket) throws WebSocketException 3311 { 3312 // Get the input stream of the socket. 3313 WebSocketInputStream input = openInputStream(socket); 3314 3315 // Get the output stream of the socket. 3316 WebSocketOutputStream output = openOutputStream(socket); 3317 3318 // Generate a value for Sec-WebSocket-Key. 3319 String key = generateWebSocketKey(); 3320 3321 // Send an opening handshake to the server. 3322 writeHandshake(output, key); 3323 3324 // Read the response from the server. 3325 Map<String, List<String>> headers = readHandshake(input, key); 3326 3327 // Keep the input stream and the output stream to pass them 3328 // to the reading thread and the writing thread later. 3329 mInput = input; 3330 mOutput = output; 3331 3332 // The handshake succeeded. 3333 return headers; 3334 } 3335 3336 3337 /** 3338 * Open the input stream of the WebSocket connection. 3339 * The stream is used by the reading thread. 3340 */ 3341 private WebSocketInputStream openInputStream(Socket socket) throws WebSocketException 3342 { 3343 try 3344 { 3345 // Get the input stream of the raw socket through which 3346 // this client receives data from the server. 3347 return new WebSocketInputStream( 3348 new BufferedInputStream(socket.getInputStream())); 3349 } 3350 catch (IOException e) 3351 { 3352 // Failed to get the input stream of the raw socket. 3353 throw new WebSocketException( 3354 WebSocketError.SOCKET_INPUT_STREAM_FAILURE, 3355 "Failed to get the input stream of the raw socket: " + e.getMessage(), e); 3356 } 3357 } 3358 3359 3360 /** 3361 * Open the output stream of the WebSocket connection. 3362 * The stream is used by the writing thread. 3363 */ 3364 private WebSocketOutputStream openOutputStream(Socket socket) throws WebSocketException 3365 { 3366 try 3367 { 3368 // Get the output stream of the socket through which 3369 // this client sends data to the server. 3370 return new WebSocketOutputStream( 3371 new BufferedOutputStream(socket.getOutputStream())); 3372 } 3373 catch (IOException e) 3374 { 3375 // Failed to get the output stream from the raw socket. 3376 throw new WebSocketException( 3377 WebSocketError.SOCKET_OUTPUT_STREAM_FAILURE, 3378 "Failed to get the output stream from the raw socket: " + e.getMessage(), e); 3379 } 3380 } 3381 3382 3383 /** 3384 * Generate a value for Sec-WebSocket-Key. 3385 * 3386 * <blockquote> 3387 * <p><i> 3388 * The request MUST include a header field with the name Sec-WebSocket-Key. 3389 * The value of this header field MUST be a nonce consisting of a randomly 3390 * selected 16-byte value that has been base64-encoded (see Section 4 of 3391 * RFC 4648). The nonce MUST be selected randomly for each connection. 3392 * </i></p> 3393 * </blockquote> 3394 * 3395 * @return 3396 * A randomly generated WebSocket key. 3397 */ 3398 private static String generateWebSocketKey() 3399 { 3400 // "16-byte value" 3401 byte[] data = new byte[16]; 3402 3403 // "randomly selected" 3404 Misc.nextBytes(data); 3405 3406 // "base64-encoded" 3407 return Base64.encode(data); 3408 } 3409 3410 3411 /** 3412 * Send an opening handshake request to the WebSocket server. 3413 */ 3414 private void writeHandshake(WebSocketOutputStream output, String key) throws WebSocketException 3415 { 3416 // Generate an opening handshake sent to the server from this client. 3417 mHandshakeBuilder.setKey(key); 3418 String requestLine = mHandshakeBuilder.buildRequestLine(); 3419 List<String[]> headers = mHandshakeBuilder.buildHeaders(); 3420 String handshake = HandshakeBuilder.build(requestLine, headers); 3421 3422 // Call onSendingHandshake() method of listeners. 3423 mListenerManager.callOnSendingHandshake(requestLine, headers); 3424 3425 try 3426 { 3427 // Send the opening handshake to the server. 3428 output.write(handshake); 3429 output.flush(); 3430 } 3431 catch (IOException e) 3432 { 3433 // Failed to send an opening handshake request to the server. 3434 throw new WebSocketException( 3435 WebSocketError.OPENING_HAHDSHAKE_REQUEST_FAILURE, 3436 "Failed to send an opening handshake request to the server: " + e.getMessage(), e); 3437 } 3438 } 3439 3440 3441 /** 3442 * Receive an opening handshake response from the WebSocket server. 3443 */ 3444 private Map<String, List<String>> readHandshake(WebSocketInputStream input, String key) throws WebSocketException 3445 { 3446 return new HandshakeReader(this).readHandshake(input, key); 3447 } 3448 3449 3450 /** 3451 * Start both the reading thread and the writing thread. 3452 * 3453 * <p> 3454 * The reading thread will call {@link #onReadingThreadStarted()} 3455 * as its first step. Likewise, the writing thread will call 3456 * {@link #onWritingThreadStarted()} as its first step. After 3457 * both the threads have started, {@link #onThreadsStarted()} is 3458 * called. 3459 * </p> 3460 */ 3461 private void startThreads() 3462 { 3463 ReadingThread readingThread = new ReadingThread(this); 3464 WritingThread writingThread = new WritingThread(this); 3465 3466 synchronized (mThreadsLock) 3467 { 3468 mReadingThread = readingThread; 3469 mWritingThread = writingThread; 3470 } 3471 3472 // Execute onThreadCreated of the listeners. 3473 readingThread.callOnThreadCreated(); 3474 writingThread.callOnThreadCreated(); 3475 3476 readingThread.start(); 3477 writingThread.start(); 3478 } 3479 3480 3481 /** 3482 * Stop both the reading thread and the writing thread. 3483 * 3484 * <p> 3485 * The reading thread will call {@link #onReadingThreadFinished(WebSocketFrame)} 3486 * as its last step. Likewise, the writing thread will call {@link 3487 * #onWritingThreadFinished(WebSocketFrame)} as its last step. 3488 * After both the threads have stopped, {@link #onThreadsFinished()} 3489 * is called. 3490 * </p> 3491 */ 3492 private void stopThreads(long closeDelay) 3493 { 3494 ReadingThread readingThread; 3495 WritingThread writingThread; 3496 3497 synchronized (mThreadsLock) 3498 { 3499 readingThread = mReadingThread; 3500 writingThread = mWritingThread; 3501 3502 mReadingThread = null; 3503 mWritingThread = null; 3504 } 3505 3506 if (readingThread != null) 3507 { 3508 readingThread.requestStop(closeDelay); 3509 } 3510 3511 if (writingThread != null) 3512 { 3513 writingThread.requestStop(); 3514 } 3515 } 3516 3517 3518 /** 3519 * Get the input stream of the WebSocket connection. 3520 */ 3521 WebSocketInputStream getInput() 3522 { 3523 return mInput; 3524 } 3525 3526 3527 /** 3528 * Get the output stream of the WebSocket connection. 3529 */ 3530 WebSocketOutputStream getOutput() 3531 { 3532 return mOutput; 3533 } 3534 3535 3536 /** 3537 * Get the manager that manages the state of this {@code WebSocket} instance. 3538 */ 3539 StateManager getStateManager() 3540 { 3541 return mStateManager; 3542 } 3543 3544 3545 /** 3546 * Get the manager that manages registered listeners. 3547 */ 3548 ListenerManager getListenerManager() 3549 { 3550 return mListenerManager; 3551 } 3552 3553 3554 /** 3555 * Get the handshake builder. {@link HandshakeReader} uses this method. 3556 */ 3557 HandshakeBuilder getHandshakeBuilder() 3558 { 3559 return mHandshakeBuilder; 3560 } 3561 3562 3563 /** 3564 * Set the agreed extensions. {@link HandshakeReader} uses this method. 3565 */ 3566 void setAgreedExtensions(List<WebSocketExtension> extensions) 3567 { 3568 mAgreedExtensions = extensions; 3569 } 3570 3571 3572 /** 3573 * Set the agreed protocol. {@link HandshakeReader} uses this method. 3574 */ 3575 void setAgreedProtocol(String protocol) 3576 { 3577 mAgreedProtocol = protocol; 3578 } 3579 3580 3581 /** 3582 * Called by the reading thread as its first step. 3583 */ 3584 void onReadingThreadStarted() 3585 { 3586 boolean bothStarted = false; 3587 3588 synchronized (mThreadsLock) 3589 { 3590 mReadingThreadStarted = true; 3591 3592 if (mWritingThreadStarted) 3593 { 3594 // Both the reading thread and the writing thread have started. 3595 bothStarted = true; 3596 } 3597 } 3598 3599 // Call onConnected() method of listeners if not called yet. 3600 callOnConnectedIfNotYet(); 3601 3602 // If both the reading thread and the writing thread have started. 3603 if (bothStarted) 3604 { 3605 onThreadsStarted(); 3606 } 3607 } 3608 3609 3610 /** 3611 * Called by the writing thread as its first step. 3612 */ 3613 void onWritingThreadStarted() 3614 { 3615 boolean bothStarted = false; 3616 3617 synchronized (mThreadsLock) 3618 { 3619 mWritingThreadStarted = true; 3620 3621 if (mReadingThreadStarted) 3622 { 3623 // Both the reading thread and the writing thread have started. 3624 bothStarted = true; 3625 } 3626 } 3627 3628 // Call onConnected() method of listeners if not called yet. 3629 callOnConnectedIfNotYet(); 3630 3631 // If both the reading thread and the writing thread have started. 3632 if (bothStarted) 3633 { 3634 onThreadsStarted(); 3635 } 3636 } 3637 3638 3639 /** 3640 * Call {@link WebSocketListener#onConnected(WebSocket, Map)} method 3641 * of the registered listeners if it has not been called yet. Either 3642 * the reading thread or the writing thread calls this method. 3643 */ 3644 private void callOnConnectedIfNotYet() 3645 { 3646 synchronized (mOnConnectedCalledLock) 3647 { 3648 // If onConnected() has already been called. 3649 if (mOnConnectedCalled) 3650 { 3651 // Do not call onConnected() twice. 3652 return; 3653 } 3654 3655 mOnConnectedCalled = true; 3656 } 3657 3658 // Notify the listeners that the handshake succeeded. 3659 mListenerManager.callOnConnected(mServerHeaders); 3660 } 3661 3662 3663 /** 3664 * Called when both the reading thread and the writing thread have started. 3665 * This method is called in the context of either the reading thread or 3666 * the writing thread. 3667 */ 3668 private void onThreadsStarted() 3669 { 3670 // Start sending ping frames periodically. 3671 // If the interval is zero, this call does nothing. 3672 mPingSender.start(); 3673 3674 // Likewise, start the pong sender. 3675 mPongSender.start(); 3676 } 3677 3678 3679 /** 3680 * Called by the reading thread as its last step. 3681 */ 3682 void onReadingThreadFinished(WebSocketFrame closeFrame) 3683 { 3684 synchronized (mThreadsLock) 3685 { 3686 mReadingThreadFinished = true; 3687 mServerCloseFrame = closeFrame; 3688 3689 if (mWritingThreadFinished == false) 3690 { 3691 // Wait for the writing thread to finish. 3692 return; 3693 } 3694 } 3695 3696 // Both the reading thread and the writing thread have finished. 3697 onThreadsFinished(); 3698 } 3699 3700 3701 /** 3702 * Called by the writing thread as its last step. 3703 */ 3704 void onWritingThreadFinished(WebSocketFrame closeFrame) 3705 { 3706 synchronized (mThreadsLock) 3707 { 3708 mWritingThreadFinished = true; 3709 mClientCloseFrame = closeFrame; 3710 3711 if (mReadingThreadFinished == false) 3712 { 3713 // Wait for the reading thread to finish. 3714 return; 3715 } 3716 } 3717 3718 // Both the reading thread and the writing thread have finished. 3719 onThreadsFinished(); 3720 } 3721 3722 3723 /** 3724 * Called when both the reading thread and the writing thread have finished. 3725 * This method is called in the context of either the reading thread or 3726 * the writing thread. 3727 */ 3728 private void onThreadsFinished() 3729 { 3730 finish(); 3731 } 3732 3733 3734 void finish() 3735 { 3736 // Stop the ping sender and the pong sender. 3737 mPingSender.stop(); 3738 mPongSender.stop(); 3739 3740 // Close the raw socket. 3741 Socket socket = mSocketConnector.getSocket(); 3742 if (socket != null) 3743 { 3744 try 3745 { 3746 socket.close(); 3747 } 3748 catch (Throwable t) 3749 { 3750 // Ignore any error raised by close(). 3751 } 3752 } 3753 3754 synchronized (mStateManager) 3755 { 3756 // Change the state to CLOSED. 3757 mStateManager.setState(CLOSED); 3758 } 3759 3760 // Notify the listeners of the state change. 3761 mListenerManager.callOnStateChanged(CLOSED); 3762 3763 // Notify the listeners that the WebSocket was disconnected. 3764 mListenerManager.callOnDisconnected( 3765 mServerCloseFrame, mClientCloseFrame, mStateManager.getClosedByServer()); 3766 } 3767 3768 3769 /** 3770 * Call {@link #finish()} from within a separate thread. 3771 */ 3772 private void finishAsynchronously() 3773 { 3774 WebSocketThread thread = new FinishThread(this); 3775 3776 // Execute onThreadCreated() of the listeners. 3777 thread.callOnThreadCreated(); 3778 3779 thread.start(); 3780 } 3781 3782 3783 /** 3784 * Find a per-message compression extension from among the agreed extensions. 3785 */ 3786 private PerMessageCompressionExtension findAgreedPerMessageCompressionExtension() 3787 { 3788 if (mAgreedExtensions == null) 3789 { 3790 return null; 3791 } 3792 3793 for (WebSocketExtension extension : mAgreedExtensions) 3794 { 3795 if (extension instanceof PerMessageCompressionExtension) 3796 { 3797 return (PerMessageCompressionExtension)extension; 3798 } 3799 } 3800 3801 return null; 3802 } 3803 3804 3805 /** 3806 * Get the PerMessageCompressionExtension in the agreed extensions. 3807 * This method returns null if a per-message compression extension 3808 * is not found in the agreed extensions. 3809 */ 3810 PerMessageCompressionExtension getPerMessageCompressionExtension() 3811 { 3812 return mPerMessageCompressionExtension; 3813 } 3814}