1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 namespace IceInternal 6 { 7 using System; 8 using System.Diagnostics; 9 using System.Net.Sockets; 10 using System.Security.Cryptography; 11 using System.Text; 12 13 sealed class WSTransceiver : Transceiver 14 { fd()15 public Socket fd() 16 { 17 return _delegate.fd(); 18 } 19 initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)20 public int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData) 21 { 22 // 23 // Delegate logs exceptions that occur during initialize(), so there's no need to trap them here. 24 // 25 if(_state == StateInitializeDelegate) 26 { 27 int op = _delegate.initialize(readBuffer, writeBuffer, ref hasMoreData); 28 if(op != 0) 29 { 30 return op; 31 } 32 _state = StateConnected; 33 } 34 35 try 36 { 37 if(_state == StateConnected) 38 { 39 // 40 // We don't know how much we'll need to read. 41 // 42 _readBuffer.resize(1024, true); 43 _readBuffer.b.position(0); 44 _readBufferPos = 0; 45 46 // 47 // The server waits for the client's upgrade request, the 48 // client sends the upgrade request. 49 // 50 _state = StateUpgradeRequestPending; 51 if(!_incoming) 52 { 53 // 54 // Compose the upgrade request. 55 // 56 StringBuilder @out = new StringBuilder(); 57 @out.Append("GET " + _resource + " HTTP/1.1\r\n"); 58 @out.Append("Host: " + _host + "\r\n"); 59 @out.Append("Upgrade: websocket\r\n"); 60 @out.Append("Connection: Upgrade\r\n"); 61 @out.Append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n"); 62 @out.Append("Sec-WebSocket-Version: 13\r\n"); 63 @out.Append("Sec-WebSocket-Key: "); 64 65 // 66 // The value for Sec-WebSocket-Key is a 16-byte random number, 67 // encoded with Base64. 68 // 69 byte[] key = new byte[16]; 70 _rand.NextBytes(key); 71 _key = System.Convert.ToBase64String(key); 72 @out.Append(_key + "\r\n\r\n"); // EOM 73 74 byte[] bytes = _utf8.GetBytes(@out.ToString()); 75 _writeBuffer.resize(bytes.Length, false); 76 _writeBuffer.b.position(0); 77 _writeBuffer.b.put(bytes); 78 _writeBuffer.b.flip(); 79 } 80 } 81 82 // 83 // Try to write the client's upgrade request. 84 // 85 if(_state == StateUpgradeRequestPending && !_incoming) 86 { 87 if(_writeBuffer.b.hasRemaining()) 88 { 89 int s = _delegate.write(_writeBuffer); 90 if(s != 0) 91 { 92 return s; 93 } 94 } 95 Debug.Assert(!_writeBuffer.b.hasRemaining()); 96 _state = StateUpgradeResponsePending; 97 } 98 99 while(true) 100 { 101 if(_readBuffer.b.hasRemaining()) 102 { 103 int s = _delegate.read(_readBuffer, ref hasMoreData); 104 if(s == SocketOperation.Write || _readBuffer.b.position() == 0) 105 { 106 return s; 107 } 108 } 109 110 // 111 // Try to read the client's upgrade request or the server's response. 112 // 113 if((_state == StateUpgradeRequestPending && _incoming) || 114 (_state == StateUpgradeResponsePending && !_incoming)) 115 { 116 // 117 // Check if we have enough data for a complete message. 118 // 119 int p = _parser.isCompleteMessage(_readBuffer.b, 0, _readBuffer.b.position()); 120 if(p == -1) 121 { 122 if(_readBuffer.b.hasRemaining()) 123 { 124 return SocketOperation.Read; 125 } 126 127 // 128 // Enlarge the buffer and try to read more. 129 // 130 int oldSize = _readBuffer.b.position(); 131 if(oldSize + 1024 > _instance.messageSizeMax()) 132 { 133 throw new Ice.MemoryLimitException(); 134 } 135 _readBuffer.resize(oldSize + 1024, true); 136 _readBuffer.b.position(oldSize); 137 continue; // Try again to read the response/request 138 } 139 140 // 141 // Set _readBufferPos at the end of the response/request message. 142 // 143 _readBufferPos = p; 144 } 145 146 // 147 // We're done, the client's upgrade request or server's response is read. 148 // 149 break; 150 } 151 152 try 153 { 154 // 155 // Parse the client's upgrade request. 156 // 157 if(_state == StateUpgradeRequestPending && _incoming) 158 { 159 if(_parser.parse(_readBuffer.b, 0, _readBufferPos)) 160 { 161 handleRequest(_writeBuffer); 162 _state = StateUpgradeResponsePending; 163 } 164 else 165 { 166 throw new Ice.ProtocolException("incomplete request message"); 167 } 168 } 169 170 if(_state == StateUpgradeResponsePending) 171 { 172 if(_incoming) 173 { 174 if(_writeBuffer.b.hasRemaining()) 175 { 176 int s = _delegate.write(_writeBuffer); 177 if(s != 0) 178 { 179 return s; 180 } 181 } 182 } 183 else 184 { 185 // 186 // Parse the server's response 187 // 188 if(_parser.parse(_readBuffer.b, 0, _readBufferPos)) 189 { 190 handleResponse(); 191 } 192 else 193 { 194 throw new Ice.ProtocolException("incomplete response message"); 195 } 196 } 197 } 198 } 199 catch(WebSocketException ex) 200 { 201 throw new Ice.ProtocolException(ex.Message); 202 } 203 204 _state = StateOpened; 205 _nextState = StateOpened; 206 207 hasMoreData = _readBufferPos < _readBuffer.b.position(); 208 } 209 catch(Ice.LocalException ex) 210 { 211 if(_instance.traceLevel() >= 2) 212 { 213 _instance.logger().trace(_instance.traceCategory(), 214 protocol() + " connection HTTP upgrade request failed\n" + ToString() + "\n" + ex); 215 } 216 throw; 217 } 218 219 if(_instance.traceLevel() >= 1) 220 { 221 if(_incoming) 222 { 223 _instance.logger().trace(_instance.traceCategory(), 224 "accepted " + protocol() + " connection HTTP upgrade request\n" + ToString()); 225 } 226 else 227 { 228 _instance.logger().trace(_instance.traceCategory(), 229 protocol() + " connection HTTP upgrade request accepted\n" + ToString()); 230 } 231 } 232 233 return SocketOperation.None; 234 } 235 closing(bool initiator, Ice.LocalException reason)236 public int closing(bool initiator, Ice.LocalException reason) 237 { 238 if(_instance.traceLevel() >= 1) 239 { 240 _instance.logger().trace(_instance.traceCategory(), 241 "gracefully closing " + protocol() + " connection\n" + ToString()); 242 } 243 244 int s = _nextState == StateOpened ? _state : _nextState; 245 246 if(s == StateClosingRequestPending && _closingInitiator) 247 { 248 // 249 // If we initiated a close connection but also received a 250 // close connection, we assume we didn't initiated the 251 // connection and we send the close frame now. This is to 252 // ensure that if both peers close the connection at the same 253 // time we don't hang having both peer waiting for the close 254 // frame of the other. 255 // 256 Debug.Assert(!initiator); 257 _closingInitiator = false; 258 return SocketOperation.Write; 259 } 260 else if(s >= StateClosingRequestPending) 261 { 262 return SocketOperation.None; 263 } 264 265 _closingInitiator = initiator; 266 if(reason is Ice.CloseConnectionException) 267 { 268 _closingReason = CLOSURE_NORMAL; 269 } 270 else if(reason is Ice.ObjectAdapterDeactivatedException || 271 reason is Ice.CommunicatorDestroyedException) 272 { 273 _closingReason = CLOSURE_SHUTDOWN; 274 } 275 else if(reason is Ice.ProtocolException) 276 { 277 _closingReason = CLOSURE_PROTOCOL_ERROR; 278 } 279 else if(reason is Ice.MemoryLimitException) 280 { 281 _closingReason = CLOSURE_TOO_BIG; 282 } 283 284 if(_state == StateOpened) 285 { 286 _state = StateClosingRequestPending; 287 return initiator ? SocketOperation.Read : SocketOperation.Write; 288 } 289 else 290 { 291 _nextState = StateClosingRequestPending; 292 return SocketOperation.None; 293 } 294 } 295 close()296 public void close() 297 { 298 _delegate.close(); 299 _state = StateClosed; 300 301 // 302 // Clear the buffers now instead of waiting for destruction. 303 // 304 if(!_readPending) 305 { 306 _readBuffer.clear(); 307 } 308 if(!_writePending) 309 { 310 _writeBuffer.clear(); 311 } 312 } 313 bind()314 public EndpointI bind() 315 { 316 Debug.Assert(false); 317 return null; 318 } 319 destroy()320 public void destroy() 321 { 322 _delegate.destroy(); 323 } 324 write(Buffer buf)325 public int write(Buffer buf) 326 { 327 if(_writePending) 328 { 329 return SocketOperation.Write; 330 } 331 332 if(_state < StateOpened) 333 { 334 if(_state < StateConnected) 335 { 336 return _delegate.write(buf); 337 } 338 else 339 { 340 return _delegate.write(_writeBuffer); 341 } 342 } 343 344 int s = SocketOperation.None; 345 do 346 { 347 if(preWrite(buf)) 348 { 349 if(_writeState == WriteStateFlush) 350 { 351 // 352 // Invoke write() even though there's nothing to write. 353 // 354 Debug.Assert(!buf.b.hasRemaining()); 355 s = _delegate.write(buf); 356 } 357 358 if(s == SocketOperation.None && _writeBuffer.b.hasRemaining()) 359 { 360 s = _delegate.write(_writeBuffer); 361 } 362 else if(s == SocketOperation.None && _incoming && !buf.empty() && _writeState == WriteStatePayload) 363 { 364 s = _delegate.write(buf); 365 } 366 } 367 } 368 while(postWrite(buf, s)); 369 370 if(s != SocketOperation.None) 371 { 372 return s; 373 } 374 if(_state == StateClosingResponsePending && !_closingInitiator) 375 { 376 return SocketOperation.Read; 377 } 378 return SocketOperation.None; 379 } 380 read(Buffer buf, ref bool hasMoreData)381 public int read(Buffer buf, ref bool hasMoreData) 382 { 383 if(_readPending) 384 { 385 return SocketOperation.Read; 386 } 387 388 if(_state < StateOpened) 389 { 390 if(_state < StateConnected) 391 { 392 return _delegate.read(buf, ref hasMoreData); 393 } 394 else 395 { 396 if(_delegate.read(_readBuffer, ref hasMoreData) == SocketOperation.Write) 397 { 398 return SocketOperation.Write; 399 } 400 else 401 { 402 return SocketOperation.None; 403 } 404 } 405 } 406 407 if(!buf.b.hasRemaining()) 408 { 409 hasMoreData |= _readBufferPos < _readBuffer.b.position(); 410 return SocketOperation.None; 411 } 412 413 int s = SocketOperation.None; 414 do 415 { 416 if(preRead(buf)) 417 { 418 if(_readState == ReadStatePayload) 419 { 420 // 421 // If the payload length is smaller than what remains to be read, we read 422 // no more than the payload length. The remaining of the buffer will be 423 // sent over in another frame. 424 // 425 int readSz = _readPayloadLength - (buf.b.position() - _readStart); 426 if(buf.b.remaining() > readSz) 427 { 428 int size = buf.size(); 429 buf.resize(buf.b.position() + readSz, true); 430 s = _delegate.read(buf, ref hasMoreData); 431 buf.resize(size, true); 432 } 433 else 434 { 435 s = _delegate.read(buf, ref hasMoreData); 436 } 437 } 438 else 439 { 440 s = _delegate.read(_readBuffer, ref hasMoreData); 441 } 442 443 if(s == SocketOperation.Write) 444 { 445 postRead(buf); 446 return s; 447 } 448 } 449 } 450 while(postRead(buf)); 451 452 if(!buf.b.hasRemaining()) 453 { 454 hasMoreData |= _readBufferPos < _readBuffer.b.position(); 455 s = SocketOperation.None; 456 } 457 else 458 { 459 hasMoreData = false; 460 s = SocketOperation.Read; 461 } 462 463 if(((_state == StateClosingRequestPending && !_closingInitiator) || 464 (_state == StateClosingResponsePending && _closingInitiator) || 465 _state == StatePingPending || 466 _state == StatePongPending) && 467 _writeState == WriteStateHeader) 468 { 469 // We have things to write, ask to be notified when writes are ready. 470 s |= SocketOperation.Write; 471 } 472 473 return s; 474 } 475 startRead(Buffer buf, AsyncCallback callback, object state)476 public bool startRead(Buffer buf, AsyncCallback callback, object state) 477 { 478 _readPending = true; 479 if(_state < StateOpened) 480 { 481 _finishRead = true; 482 if(_state < StateConnected) 483 { 484 return _delegate.startRead(buf, callback, state); 485 } 486 else 487 { 488 return _delegate.startRead(_readBuffer, callback, state); 489 } 490 } 491 492 if(preRead(buf)) 493 { 494 _finishRead = true; 495 if(_readState == ReadStatePayload) 496 { 497 // 498 // If the payload length is smaller than what remains to be read, we read 499 // no more than the payload length. The remaining of the buffer will be 500 // sent over in another frame. 501 // 502 int readSz = _readPayloadLength - (buf.b.position() - _readStart); 503 if(buf.b.remaining() > readSz) 504 { 505 int size = buf.size(); 506 buf.resize(buf.b.position() + readSz, true); 507 bool completedSynchronously = _delegate.startRead(buf, callback, state); 508 buf.resize(size, true); 509 return completedSynchronously; 510 } 511 else 512 { 513 return _delegate.startRead(buf, callback, state); 514 } 515 } 516 else 517 { 518 return _delegate.startRead(_readBuffer, callback, state); 519 } 520 } 521 else 522 { 523 return true; 524 } 525 } 526 finishRead(Buffer buf)527 public void finishRead(Buffer buf) 528 { 529 Debug.Assert(_readPending); 530 _readPending = false; 531 532 if(_state < StateOpened) 533 { 534 Debug.Assert(_finishRead); 535 _finishRead = false; 536 if(_state < StateConnected) 537 { 538 _delegate.finishRead(buf); 539 } 540 else 541 { 542 _delegate.finishRead(_readBuffer); 543 } 544 return; 545 } 546 547 if(!_finishRead) 548 { 549 // Nothing to do. 550 } 551 else if(_readState == ReadStatePayload) 552 { 553 Debug.Assert(_finishRead); 554 _finishRead = false; 555 _delegate.finishRead(buf); 556 } 557 else 558 { 559 Debug.Assert(_finishRead); 560 _finishRead = false; 561 _delegate.finishRead(_readBuffer); 562 } 563 564 if(_state == StateClosed) 565 { 566 _readBuffer.clear(); 567 return; 568 } 569 570 postRead(buf); 571 } 572 startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)573 public bool startWrite(Buffer buf, AsyncCallback callback, object state, 574 out bool completed) 575 { 576 _writePending = true; 577 if(_state < StateOpened) 578 { 579 if(_state < StateConnected) 580 { 581 return _delegate.startWrite(buf, callback, state, out completed); 582 } 583 else 584 { 585 return _delegate.startWrite(_writeBuffer, callback, state, out completed); 586 } 587 } 588 589 if(preWrite(buf)) 590 { 591 if(_writeBuffer.b.hasRemaining()) 592 { 593 return _delegate.startWrite(_writeBuffer, callback, state, out completed); 594 } 595 else 596 { 597 Debug.Assert(_incoming); 598 return _delegate.startWrite(buf, callback, state, out completed); 599 } 600 } 601 else 602 { 603 completed = true; 604 return false; 605 } 606 } 607 finishWrite(Buffer buf)608 public void finishWrite(Buffer buf) 609 { 610 _writePending = false; 611 612 if(_state < StateOpened) 613 { 614 if(_state < StateConnected) 615 { 616 _delegate.finishWrite(buf); 617 } 618 else 619 { 620 _delegate.finishWrite(_writeBuffer); 621 } 622 return; 623 } 624 625 if(_writeBuffer.b.hasRemaining()) 626 { 627 _delegate.finishWrite(_writeBuffer); 628 } 629 else if(!buf.empty() && buf.b.hasRemaining()) 630 { 631 Debug.Assert(_incoming); 632 _delegate.finishWrite(buf); 633 } 634 635 if(_state == StateClosed) 636 { 637 _writeBuffer.clear(); 638 return; 639 } 640 641 postWrite(buf, SocketOperation.None); 642 } 643 protocol()644 public string protocol() 645 { 646 return _instance.protocol(); 647 } 648 getInfo()649 public Ice.ConnectionInfo getInfo() 650 { 651 Ice.WSConnectionInfo info = new Ice.WSConnectionInfo(); 652 info.headers = _parser.getHeaders(); 653 info.underlying = _delegate.getInfo(); 654 return info; 655 } 656 checkSendSize(Buffer buf)657 public void checkSendSize(Buffer buf) 658 { 659 _delegate.checkSendSize(buf); 660 } 661 setBufferSize(int rcvSize, int sndSize)662 public void setBufferSize(int rcvSize, int sndSize) 663 { 664 _delegate.setBufferSize(rcvSize, sndSize); 665 } 666 ToString()667 public override string ToString() 668 { 669 return _delegate.ToString(); 670 } 671 toDetailedString()672 public string toDetailedString() 673 { 674 return _delegate.toDetailedString(); 675 } 676 677 internal WSTransceiver(ProtocolInstance instance, Transceiver del, string host, string resource)678 WSTransceiver(ProtocolInstance instance, Transceiver del, string host, string resource) 679 { 680 init(instance, del); 681 _host = host; 682 _resource = resource; 683 _incoming = false; 684 685 // 686 // Use a 16KB write buffer size. We use 16KB for the write 687 // buffer size because all the data needs to be copied to the 688 // write buffer for the purpose of masking. A 16KB buffer 689 // appears to be a good compromise to reduce the number of 690 // socket write calls and not consume too much memory. 691 // 692 _writeBufferSize = 16 * 1024; 693 694 // 695 // Write and read buffer size must be large enough to hold the frame header! 696 // 697 Debug.Assert(_writeBufferSize > 256); 698 Debug.Assert(_readBufferSize > 256); 699 } 700 WSTransceiver(ProtocolInstance instance, Transceiver del)701 internal WSTransceiver(ProtocolInstance instance, Transceiver del) 702 { 703 init(instance, del); 704 _host = ""; 705 _resource = ""; 706 _incoming = true; 707 708 // 709 // Write and read buffer size must be large enough to hold the frame header! 710 // 711 Debug.Assert(_writeBufferSize > 256); 712 Debug.Assert(_readBufferSize > 256); 713 } 714 init(ProtocolInstance instance, Transceiver del)715 private void init(ProtocolInstance instance, Transceiver del) 716 { 717 _instance = instance; 718 _delegate = del; 719 _state = StateInitializeDelegate; 720 _parser = new HttpParser(); 721 _readState = ReadStateOpcode; 722 _readBuffer = new Buffer(ByteBuffer.ByteOrder.BIG_ENDIAN); // Network byte order 723 _readBufferSize = 1024; 724 _readLastFrame = true; 725 _readOpCode = 0; 726 _readHeaderLength = 0; 727 _readPayloadLength = 0; 728 _writeState = WriteStateHeader; 729 _writeBuffer = new Buffer(ByteBuffer.ByteOrder.BIG_ENDIAN); // Network byte order 730 _writeBufferSize = 1024; 731 _readPending = false; 732 _finishRead = false; 733 _writePending = false; 734 _readMask = new byte[4]; 735 _writeMask = new byte[4]; 736 _key = ""; 737 _pingPayload = new byte[0]; 738 _rand = new Random(); 739 } 740 handleRequest(Buffer responseBuffer)741 private void handleRequest(Buffer responseBuffer) 742 { 743 // 744 // HTTP/1.1 745 // 746 if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1) 747 { 748 throw new WebSocketException("unsupported HTTP version"); 749 } 750 751 // 752 // "An |Upgrade| header field containing the value 'websocket', 753 // treated as an ASCII case-insensitive value." 754 // 755 string val = _parser.getHeader("Upgrade", true); 756 if(val == null) 757 { 758 throw new WebSocketException("missing value for Upgrade field"); 759 } 760 else if(!val.Equals("websocket")) 761 { 762 throw new WebSocketException("invalid value `" + val + "' for Upgrade field"); 763 } 764 765 // 766 // "A |Connection| header field that includes the token 'Upgrade', 767 // treated as an ASCII case-insensitive value. 768 // 769 val = _parser.getHeader("Connection", true); 770 if(val == null) 771 { 772 throw new WebSocketException("missing value for Connection field"); 773 } 774 else if(val.IndexOf("upgrade") == -1) 775 { 776 throw new WebSocketException("invalid value `" + val + "' for Connection field"); 777 } 778 779 // 780 // "A |Sec-WebSocket-Version| header field, with a value of 13." 781 // 782 val = _parser.getHeader("Sec-WebSocket-Version", false); 783 if(val == null) 784 { 785 throw new WebSocketException("missing value for WebSocket version"); 786 } 787 else if(!val.Equals("13")) 788 { 789 throw new WebSocketException("unsupported WebSocket version `" + val + "'"); 790 } 791 792 // 793 // "Optionally, a |Sec-WebSocket-Protocol| header field, with a list 794 // of values indicating which protocols the client would like to 795 // speak, ordered by preference." 796 // 797 bool addProtocol = false; 798 val = _parser.getHeader("Sec-WebSocket-Protocol", true); 799 if(val != null) 800 { 801 string[] protocols = IceUtilInternal.StringUtil.splitString(val, ","); 802 if(protocols == null) 803 { 804 throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol"); 805 } 806 foreach(string p in protocols) 807 { 808 if(!p.Trim().Equals(_iceProtocol)) 809 { 810 throw new WebSocketException("unknown value `" + p + "' for WebSocket protocol"); 811 } 812 addProtocol = true; 813 } 814 } 815 816 // 817 // "A |Sec-WebSocket-Key| header field with a base64-encoded 818 // value that, when decoded, is 16 bytes in length." 819 // 820 string key = _parser.getHeader("Sec-WebSocket-Key", false); 821 if(key == null) 822 { 823 throw new WebSocketException("missing value for WebSocket key"); 824 } 825 826 byte[] decodedKey = Convert.FromBase64String(key); 827 if(decodedKey.Length != 16) 828 { 829 throw new WebSocketException("invalid value `" + key + "' for WebSocket key"); 830 } 831 832 // 833 // Retain the target resource. 834 // 835 _resource = _parser.uri(); 836 837 // 838 // Compose the response. 839 // 840 StringBuilder @out = new StringBuilder(); 841 @out.Append("HTTP/1.1 101 Switching Protocols\r\n"); 842 @out.Append("Upgrade: websocket\r\n"); 843 @out.Append("Connection: Upgrade\r\n"); 844 if(addProtocol) 845 { 846 @out.Append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n"); 847 } 848 849 // 850 // The response includes: 851 // 852 // "A |Sec-WebSocket-Accept| header field. The value of this 853 // header field is constructed by concatenating /key/, defined 854 // above in step 4 in Section 4.2.2, with the string "258EAFA5- 855 // E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this 856 // concatenated value to obtain a 20-byte value and base64- 857 // encoding (see Section 4 of [RFC4648]) this 20-byte hash. 858 // 859 @out.Append("Sec-WebSocket-Accept: "); 860 string input = key + _wsUUID; 861 byte[] hash = SHA1.Create().ComputeHash(_utf8.GetBytes(input)); 862 @out.Append(Convert.ToBase64String(hash) + "\r\n" + "\r\n"); // EOM 863 864 byte[] bytes = _utf8.GetBytes(@out.ToString()); 865 Debug.Assert(bytes.Length == @out.Length); 866 responseBuffer.resize(bytes.Length, false); 867 responseBuffer.b.position(0); 868 responseBuffer.b.put(bytes); 869 responseBuffer.b.flip(); 870 } 871 handleResponse()872 private void handleResponse() 873 { 874 string val; 875 876 // 877 // HTTP/1.1 878 // 879 if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1) 880 { 881 throw new WebSocketException("unsupported HTTP version"); 882 } 883 884 // 885 // "If the status code received from the server is not 101, the 886 // client handles the response per HTTP [RFC2616] procedures. In 887 // particular, the client might perform authentication if it 888 // receives a 401 status code; the server might redirect the client 889 // using a 3xx status code (but clients are not required to follow 890 // them), etc." 891 // 892 if(_parser.status() != 101) 893 { 894 StringBuilder @out = new StringBuilder("unexpected status value " + _parser.status()); 895 if(_parser.reason().Length > 0) 896 { 897 @out.Append(":\n" + _parser.reason()); 898 } 899 throw new WebSocketException(@out.ToString()); 900 } 901 902 // 903 // "If the response lacks an |Upgrade| header field or the |Upgrade| 904 // header field contains a value that is not an ASCII case- 905 // insensitive match for the value "websocket", the client MUST 906 // _Fail the WebSocket Connection_." 907 // 908 val = _parser.getHeader("Upgrade", true); 909 if(val == null) 910 { 911 throw new WebSocketException("missing value for Upgrade field"); 912 } 913 else if(!val.Equals("websocket")) 914 { 915 throw new WebSocketException("invalid value `" + val + "' for Upgrade field"); 916 } 917 918 // 919 // "If the response lacks a |Connection| header field or the 920 // |Connection| header field doesn't contain a token that is an 921 // ASCII case-insensitive match for the value "Upgrade", the client 922 // MUST _Fail the WebSocket Connection_." 923 // 924 val = _parser.getHeader("Connection", true); 925 if(val == null) 926 { 927 throw new WebSocketException("missing value for Connection field"); 928 } 929 else if(val.IndexOf("upgrade") == -1) 930 { 931 throw new WebSocketException("invalid value `" + val + "' for Connection field"); 932 } 933 934 // 935 // "If the response includes a |Sec-WebSocket-Protocol| header field 936 // and this header field indicates the use of a subprotocol that was 937 // not present in the client's handshake (the server has indicated a 938 // subprotocol not requested by the client), the client MUST _Fail 939 // the WebSocket Connection_." 940 // 941 val = _parser.getHeader("Sec-WebSocket-Protocol", true); 942 if(val != null && !val.Equals(_iceProtocol)) 943 { 944 throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol"); 945 } 946 947 // 948 // "If the response lacks a |Sec-WebSocket-Accept| header field or 949 // the |Sec-WebSocket-Accept| contains a value other than the 950 // base64-encoded SHA-1 of the concatenation of the |Sec-WebSocket- 951 // Key| (as a string, not base64-decoded) with the string "258EAFA5- 952 // E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and 953 // trailing whitespace, the client MUST _Fail the WebSocket 954 // Connection_." 955 // 956 val = _parser.getHeader("Sec-WebSocket-Accept", false); 957 if(val == null) 958 { 959 throw new WebSocketException("missing value for Sec-WebSocket-Accept"); 960 } 961 962 string input = _key + _wsUUID; 963 byte[] hash = SHA1.Create().ComputeHash(_utf8.GetBytes(input)); 964 if(!val.Equals(Convert.ToBase64String(hash))) 965 { 966 throw new WebSocketException("invalid value `" + val + "' for Sec-WebSocket-Accept"); 967 } 968 } 969 preRead(Buffer buf)970 private bool preRead(Buffer buf) 971 { 972 while(true) 973 { 974 if(_readState == ReadStateOpcode) 975 { 976 // 977 // Is there enough data available to read the opcode? 978 // 979 if(!readBuffered(2)) 980 { 981 return true; 982 } 983 984 // 985 // Most-significant bit indicates whether this is the 986 // last frame. Least-significant four bits hold the 987 // opcode. 988 // 989 int ch = _readBuffer.b.get(_readBufferPos++); 990 _readOpCode = ch & 0xf; 991 992 // 993 // Remember if last frame if we're going to read a data or 994 // continuation frame, this is only for protocol 995 // correctness checking purpose. 996 // 997 if(_readOpCode == OP_DATA) 998 { 999 if(!_readLastFrame) 1000 { 1001 throw new Ice.ProtocolException("invalid data frame, no FIN on previous frame"); 1002 } 1003 _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL; 1004 } 1005 else if(_readOpCode == OP_CONT) 1006 { 1007 if(_readLastFrame) 1008 { 1009 throw new Ice.ProtocolException("invalid continuation frame, previous frame FIN set"); 1010 } 1011 _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL; 1012 } 1013 1014 ch = _readBuffer.b.get(_readBufferPos++); 1015 1016 // 1017 // Check the MASK bit. Messages sent by a client must be masked; 1018 // messages sent by a server must not be masked. 1019 // 1020 bool masked = (ch & FLAG_MASKED) == FLAG_MASKED; 1021 if(masked != _incoming) 1022 { 1023 throw new Ice.ProtocolException("invalid masking"); 1024 } 1025 1026 // 1027 // Extract the payload length, which can have the following values: 1028 // 1029 // 0-125: The payload length 1030 // 126: The subsequent two bytes contain the payload length 1031 // 127: The subsequent eight bytes contain the payload length 1032 // 1033 _readPayloadLength = (ch & 0x7f); 1034 if(_readPayloadLength < 126) 1035 { 1036 _readHeaderLength = 0; 1037 } 1038 else if(_readPayloadLength == 126) 1039 { 1040 _readHeaderLength = 2; // Need to read a 16-bit payload length. 1041 } 1042 else 1043 { 1044 _readHeaderLength = 8; // Need to read a 64-bit payload length. 1045 } 1046 if(masked) 1047 { 1048 _readHeaderLength += 4; // Need to read a 32-bit mask. 1049 } 1050 1051 _readState = ReadStateHeader; 1052 } 1053 1054 if(_readState == ReadStateHeader) 1055 { 1056 // 1057 // Is there enough data available to read the header? 1058 // 1059 if(_readHeaderLength > 0 && !readBuffered(_readHeaderLength)) 1060 { 1061 return true; 1062 } 1063 1064 if(_readPayloadLength == 126) 1065 { 1066 _readPayloadLength = _readBuffer.b.getShort(_readBufferPos); // Uses network byte order. 1067 if(_readPayloadLength < 0) 1068 { 1069 _readPayloadLength += 65536; 1070 } 1071 _readBufferPos += 2; 1072 } 1073 else if(_readPayloadLength == 127) 1074 { 1075 long l = _readBuffer.b.getLong(_readBufferPos); // Uses network byte order. 1076 _readBufferPos += 8; 1077 if(l < 0 || l > Int32.MaxValue) 1078 { 1079 throw new Ice.ProtocolException("invalid WebSocket payload length: " + l); 1080 } 1081 _readPayloadLength = (int)l; 1082 } 1083 1084 // 1085 // Read the mask if this is an incoming connection. 1086 // 1087 if(_incoming) 1088 { 1089 // 1090 // We must have needed to read the mask. 1091 // 1092 Debug.Assert(_readBuffer.b.position() - _readBufferPos >= 4); 1093 for(int i = 0; i < 4; ++i) 1094 { 1095 _readMask[i] = _readBuffer.b.get(_readBufferPos++); // Copy the mask. 1096 } 1097 } 1098 1099 switch(_readOpCode) 1100 { 1101 case OP_TEXT: // Text frame 1102 { 1103 throw new Ice.ProtocolException("text frames not supported"); 1104 } 1105 case OP_DATA: // Data frame 1106 case OP_CONT: // Continuation frame 1107 { 1108 if(_instance.traceLevel() >= 2) 1109 { 1110 _instance.logger().trace(_instance.traceCategory(), "received " + protocol() + 1111 (_readOpCode == OP_DATA ? " data" : " continuation") + 1112 " frame with payload length of " + _readPayloadLength + 1113 " bytes\n" + ToString()); 1114 } 1115 1116 if(_readPayloadLength <= 0) 1117 { 1118 throw new Ice.ProtocolException("payload length is 0"); 1119 } 1120 _readState = ReadStatePayload; 1121 Debug.Assert(buf.b.hasRemaining()); 1122 _readFrameStart = buf.b.position(); 1123 break; 1124 } 1125 case OP_CLOSE: // Connection close 1126 { 1127 if(_instance.traceLevel() >= 2) 1128 { 1129 _instance.logger().trace(_instance.traceCategory(), 1130 "received " + protocol() + " connection close frame\n" + ToString()); 1131 } 1132 1133 _readState = ReadStateControlFrame; 1134 int s = _nextState == StateOpened ? _state : _nextState; 1135 if(s == StateClosingRequestPending) 1136 { 1137 // 1138 // If we receive a close frame while we were actually 1139 // waiting to send one, change the role and send a 1140 // close frame response. 1141 // 1142 if(!_closingInitiator) 1143 { 1144 _closingInitiator = true; 1145 } 1146 if(_state == StateClosingRequestPending) 1147 { 1148 _state = StateClosingResponsePending; 1149 } 1150 else 1151 { 1152 _nextState = StateClosingResponsePending; 1153 } 1154 return false; // No longer interested in reading 1155 } 1156 else 1157 { 1158 throw new Ice.ConnectionLostException(); 1159 } 1160 } 1161 case OP_PING: 1162 { 1163 if(_instance.traceLevel() >= 2) 1164 { 1165 _instance.logger().trace(_instance.traceCategory(), 1166 "received " + protocol() + " connection ping frame\n" + ToString()); 1167 } 1168 _readState = ReadStateControlFrame; 1169 break; 1170 } 1171 case OP_PONG: // Pong 1172 { 1173 if(_instance.traceLevel() >= 2) 1174 { 1175 _instance.logger().trace(_instance.traceCategory(), 1176 "received " + protocol() + " connection pong frame\n" + ToString()); 1177 } 1178 _readState = ReadStateControlFrame; 1179 break; 1180 } 1181 default: 1182 { 1183 throw new Ice.ProtocolException("unsupported opcode: " + _readOpCode); 1184 } 1185 } 1186 } 1187 1188 if(_readState == ReadStateControlFrame) 1189 { 1190 if(_readPayloadLength > 0 && !readBuffered(_readPayloadLength)) 1191 { 1192 return true; 1193 } 1194 1195 if(_readPayloadLength > 0 && _readOpCode == OP_PING) 1196 { 1197 _pingPayload = new byte[_readPayloadLength]; 1198 System.Buffer.BlockCopy(_readBuffer.b.rawBytes(), _readBufferPos, _pingPayload, 0, 1199 _readPayloadLength); 1200 } 1201 1202 _readBufferPos += _readPayloadLength; 1203 _readPayloadLength = 0; 1204 1205 if(_readOpCode == OP_PING) 1206 { 1207 if(_state == StateOpened) 1208 { 1209 _state = StatePongPending; // Send pong frame now 1210 } 1211 else if(_nextState < StatePongPending) 1212 { 1213 _nextState = StatePongPending; // Send pong frame next 1214 } 1215 } 1216 1217 // 1218 // We've read the payload of the PING/PONG frame, we're ready 1219 // to read a new frame. 1220 // 1221 _readState = ReadStateOpcode; 1222 } 1223 1224 if(_readState == ReadStatePayload) 1225 { 1226 // 1227 // This must be assigned before the check for the buffer. If the buffer is empty 1228 // or already read, postRead will return false. 1229 // 1230 _readStart = buf.b.position(); 1231 1232 if(buf.empty() || !buf.b.hasRemaining()) 1233 { 1234 return false; 1235 } 1236 1237 int n = Math.Min(_readBuffer.b.position() - _readBufferPos, buf.b.remaining()); 1238 if(n > _readPayloadLength) 1239 { 1240 n = _readPayloadLength; 1241 } 1242 if(n > 0) 1243 { 1244 System.Buffer.BlockCopy(_readBuffer.b.rawBytes(), _readBufferPos, buf.b.rawBytes(), 1245 buf.b.position(), n); 1246 buf.b.position(buf.b.position() + n); 1247 _readBufferPos += n; 1248 } 1249 1250 // 1251 // Continue reading if we didn't read the full message, otherwise give back 1252 // the control to the connection 1253 // 1254 return buf.b.hasRemaining() && n < _readPayloadLength; 1255 } 1256 } 1257 } 1258 postRead(Buffer buf)1259 private bool postRead(Buffer buf) 1260 { 1261 if(_readState != ReadStatePayload) 1262 { 1263 return _readStart < _readBuffer.b.position(); // Returns true if data was read. 1264 } 1265 1266 if(_readStart == buf.b.position()) 1267 { 1268 return false; // Nothing was read or nothing to read. 1269 } 1270 Debug.Assert(_readStart < buf.b.position()); 1271 1272 if(_incoming) 1273 { 1274 // 1275 // Unmask the data we just read. 1276 // 1277 int pos = buf.b.position(); 1278 byte[] arr = buf.b.rawBytes(); 1279 for(int n = _readStart; n < pos; ++n) 1280 { 1281 arr[n] = (byte)(arr[n] ^ _readMask[(n - _readFrameStart) % 4]); 1282 } 1283 } 1284 1285 _readPayloadLength -= buf.b.position() - _readStart; 1286 _readStart = buf.b.position(); 1287 if(_readPayloadLength == 0) 1288 { 1289 // 1290 // We've read the complete payload, we're ready to read a new frame. 1291 // 1292 _readState = ReadStateOpcode; 1293 } 1294 return buf.b.hasRemaining(); 1295 } 1296 preWrite(Buffer buf)1297 private bool preWrite(Buffer buf) 1298 { 1299 if(_writeState == WriteStateHeader) 1300 { 1301 if(_state == StateOpened) 1302 { 1303 if(buf.empty() || !buf.b.hasRemaining()) 1304 { 1305 return false; 1306 } 1307 1308 Debug.Assert(buf.b.position() == 0); 1309 prepareWriteHeader((byte)OP_DATA, buf.size()); 1310 1311 _writeState = WriteStatePayload; 1312 } 1313 else if(_state == StatePingPending) 1314 { 1315 prepareWriteHeader((byte)OP_PING, 0); // Don't send any payload 1316 1317 _writeState = WriteStateControlFrame; 1318 _writeBuffer.b.flip(); 1319 } 1320 else if(_state == StatePongPending) 1321 { 1322 prepareWriteHeader((byte)OP_PONG, _pingPayload.Length); 1323 if(_pingPayload.Length > _writeBuffer.b.remaining()) 1324 { 1325 int pos = _writeBuffer.b.position(); 1326 _writeBuffer.resize(pos + _pingPayload.Length, false); 1327 _writeBuffer.b.position(pos); 1328 } 1329 _writeBuffer.b.put(_pingPayload); 1330 _pingPayload = new byte[0]; 1331 1332 _writeState = WriteStateControlFrame; 1333 _writeBuffer.b.flip(); 1334 } 1335 else if((_state == StateClosingRequestPending && !_closingInitiator) || 1336 (_state == StateClosingResponsePending && _closingInitiator)) 1337 { 1338 prepareWriteHeader((byte)OP_CLOSE, 2); 1339 1340 // Write closing reason 1341 _writeBuffer.b.putShort((short)_closingReason); 1342 1343 if(!_incoming) 1344 { 1345 byte b; 1346 int pos = _writeBuffer.b.position() - 2; 1347 b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[0]); 1348 _writeBuffer.b.put(pos, b); 1349 pos++; 1350 b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[1]); 1351 _writeBuffer.b.put(pos, b); 1352 } 1353 1354 _writeState = WriteStateControlFrame; 1355 _writeBuffer.b.flip(); 1356 } 1357 else 1358 { 1359 Debug.Assert(_state != StateClosed); 1360 return false; // Nothing to write in this state 1361 } 1362 1363 _writePayloadLength = 0; 1364 } 1365 1366 if(_writeState == WriteStatePayload) 1367 { 1368 // 1369 // For an outgoing connection, each message must be masked with a random 1370 // 32-bit value, so we copy the entire message into the internal buffer 1371 // for writing. For incoming connections, we just copy the start of the 1372 // message in the internal buffer after the hedaer. If the message is 1373 // larger, the reminder is sent directly from the message buffer to avoid 1374 // copying. 1375 // 1376 if(!_incoming && (_writePayloadLength == 0 || !_writeBuffer.b.hasRemaining())) 1377 { 1378 if(!_writeBuffer.b.hasRemaining()) 1379 { 1380 _writeBuffer.b.position(0); 1381 } 1382 1383 int n = buf.b.position(); 1384 int sz = buf.size(); 1385 int pos = _writeBuffer.b.position(); 1386 int count = Math.Min(sz - n, _writeBuffer.b.remaining()); 1387 byte[] src = buf.b.rawBytes(); 1388 byte[] dest = _writeBuffer.b.rawBytes(); 1389 for(int i = 0; i < count; ++i, ++n, ++pos) 1390 { 1391 dest[pos] = (byte)(src[n] ^ _writeMask[n % 4]); 1392 } 1393 _writeBuffer.b.position(pos); 1394 _writePayloadLength = n; 1395 1396 _writeBuffer.b.flip(); 1397 } 1398 else if(_writePayloadLength == 0) 1399 { 1400 Debug.Assert(_incoming); 1401 if(_writeBuffer.b.hasRemaining()) 1402 { 1403 Debug.Assert(buf.b.position() == 0); 1404 int n = Math.Min(_writeBuffer.b.remaining(), buf.b.remaining()); 1405 int pos = _writeBuffer.b.position(); 1406 System.Buffer.BlockCopy(buf.b.rawBytes(), 0, _writeBuffer.b.rawBytes(), pos, n); 1407 _writeBuffer.b.position(pos + n); 1408 _writePayloadLength = n; 1409 } 1410 _writeBuffer.b.flip(); 1411 } 1412 return true; 1413 } 1414 else if(_writeState == WriteStateControlFrame) 1415 { 1416 return _writeBuffer.b.hasRemaining(); 1417 } 1418 else 1419 { 1420 Debug.Assert(_writeState == WriteStateFlush); 1421 return true; 1422 } 1423 } 1424 postWrite(Buffer buf, int status)1425 private bool postWrite(Buffer buf, int status) 1426 { 1427 if(_state > StateOpened && _writeState == WriteStateControlFrame) 1428 { 1429 if(!_writeBuffer.b.hasRemaining()) 1430 { 1431 if(_state == StatePingPending) 1432 { 1433 if(_instance.traceLevel() >= 2) 1434 { 1435 _instance.logger().trace(_instance.traceCategory(), 1436 "sent " + protocol() + " connection ping frame\n" + ToString()); 1437 } 1438 } 1439 else if(_state == StatePongPending) 1440 { 1441 if(_instance.traceLevel() >= 2) 1442 { 1443 _instance.logger().trace(_instance.traceCategory(), 1444 "sent " + protocol() + " connection pong frame\n" + ToString()); 1445 } 1446 } 1447 else if((_state == StateClosingRequestPending && !_closingInitiator) || 1448 (_state == StateClosingResponsePending && _closingInitiator)) 1449 { 1450 if(_instance.traceLevel() >= 2) 1451 { 1452 _instance.logger().trace(_instance.traceCategory(), 1453 "sent " + protocol() + " connection close frame\n" + ToString()); 1454 } 1455 1456 if(_state == StateClosingRequestPending && !_closingInitiator) 1457 { 1458 _writeState = WriteStateHeader; 1459 _state = StateClosingResponsePending; 1460 return false; 1461 } 1462 else 1463 { 1464 throw new Ice.ConnectionLostException(); 1465 } 1466 } 1467 else if(_state == StateClosed) 1468 { 1469 return false; 1470 } 1471 1472 _state = _nextState; 1473 _nextState = StateOpened; 1474 _writeState = WriteStateHeader; 1475 } 1476 else 1477 { 1478 return status == SocketOperation.None; 1479 } 1480 } 1481 1482 if((!_incoming || buf.b.position() == 0) && _writePayloadLength > 0) 1483 { 1484 if(!_writeBuffer.b.hasRemaining()) 1485 { 1486 buf.b.position(_writePayloadLength); 1487 } 1488 } 1489 1490 if(status == SocketOperation.Write && !buf.b.hasRemaining() && !_writeBuffer.b.hasRemaining()) 1491 { 1492 // 1493 // Our buffers are empty but the delegate needs another call to write(). 1494 // 1495 _writeState = WriteStateFlush; 1496 return false; 1497 } 1498 else if(!buf.b.hasRemaining()) 1499 { 1500 _writeState = WriteStateHeader; 1501 if(_state == StatePingPending || 1502 _state == StatePongPending || 1503 (_state == StateClosingRequestPending && !_closingInitiator) || 1504 (_state == StateClosingResponsePending && _closingInitiator)) 1505 { 1506 return true; 1507 } 1508 } 1509 else if(_state == StateOpened) 1510 { 1511 return status == SocketOperation.None; 1512 } 1513 1514 return false; 1515 } 1516 readBuffered(int sz)1517 private bool readBuffered(int sz) 1518 { 1519 if(_readBufferPos == _readBuffer.b.position()) 1520 { 1521 _readBuffer.resize(_readBufferSize, true); 1522 _readBufferPos = 0; 1523 _readBuffer.b.position(0); 1524 } 1525 else 1526 { 1527 int available = _readBuffer.b.position() - _readBufferPos; 1528 if(available < sz) 1529 { 1530 if(_readBufferPos > 0) 1531 { 1532 _readBuffer.b.limit(_readBuffer.b.position()); 1533 _readBuffer.b.position(_readBufferPos); 1534 _readBuffer.b.compact(); 1535 Debug.Assert(_readBuffer.b.position() == available); 1536 } 1537 _readBuffer.resize(Math.Max(_readBufferSize, sz), true); 1538 _readBufferPos = 0; 1539 _readBuffer.b.position(available); 1540 } 1541 } 1542 1543 _readStart = _readBuffer.b.position(); 1544 if(_readBufferPos + sz > _readBuffer.b.position()) 1545 { 1546 return false; // Not enough read. 1547 } 1548 Debug.Assert(_readBuffer.b.position() > _readBufferPos); 1549 return true; 1550 } 1551 prepareWriteHeader(byte opCode, int payloadLength)1552 private void prepareWriteHeader(byte opCode, int payloadLength) 1553 { 1554 // 1555 // We need to prepare the frame header. 1556 // 1557 _writeBuffer.resize(_writeBufferSize, false); 1558 _writeBuffer.b.limit(_writeBufferSize); 1559 _writeBuffer.b.position(0); 1560 1561 // 1562 // Set the opcode - this is the one and only data frame. 1563 // 1564 _writeBuffer.b.put((byte)(opCode | FLAG_FINAL)); 1565 1566 // 1567 // Set the payload length. 1568 // 1569 if(payloadLength <= 125) 1570 { 1571 _writeBuffer.b.put((byte)payloadLength); 1572 } 1573 else if(payloadLength > 125 && payloadLength <= 65535) 1574 { 1575 // 1576 // Use an extra 16 bits to encode the payload length. 1577 // 1578 _writeBuffer.b.put(126); 1579 _writeBuffer.b.putShort((short)payloadLength); 1580 } 1581 else if(payloadLength > 65535) 1582 { 1583 // 1584 // Use an extra 64 bits to encode the payload length. 1585 // 1586 _writeBuffer.b.put(127); 1587 _writeBuffer.b.putLong(payloadLength); 1588 } 1589 1590 if(!_incoming) 1591 { 1592 // 1593 // Add a random 32-bit mask to every outgoing frame, copy the payload data, 1594 // and apply the mask. 1595 // 1596 _writeBuffer.b.put(1, (byte)(_writeBuffer.b.get(1) | FLAG_MASKED)); 1597 _rand.NextBytes(_writeMask); 1598 _writeBuffer.b.put(_writeMask); 1599 } 1600 } 1601 1602 private ProtocolInstance _instance; 1603 private Transceiver _delegate; 1604 private string _host; 1605 private string _resource; 1606 private bool _incoming; 1607 1608 private const int StateInitializeDelegate = 0; 1609 private const int StateConnected = 1; 1610 private const int StateUpgradeRequestPending = 2; 1611 private const int StateUpgradeResponsePending = 3; 1612 private const int StateOpened = 4; 1613 private const int StatePingPending = 5; 1614 private const int StatePongPending = 6; 1615 private const int StateClosingRequestPending = 7; 1616 private const int StateClosingResponsePending = 8; 1617 private const int StateClosed = 9; 1618 1619 private int _state; 1620 private int _nextState; 1621 1622 private HttpParser _parser; 1623 private string _key; 1624 1625 private const int ReadStateOpcode = 0; 1626 private const int ReadStateHeader = 1; 1627 private const int ReadStateControlFrame = 2; 1628 private const int ReadStatePayload = 3; 1629 1630 private int _readState; 1631 private Buffer _readBuffer; 1632 private int _readBufferPos; 1633 private int _readBufferSize; 1634 1635 private bool _readLastFrame; 1636 private int _readOpCode; 1637 private int _readHeaderLength; 1638 private int _readPayloadLength; 1639 private int _readStart; 1640 private int _readFrameStart; 1641 private byte[] _readMask; 1642 1643 private const int WriteStateHeader = 0; 1644 private const int WriteStatePayload = 1; 1645 private const int WriteStateControlFrame = 2; 1646 private const int WriteStateFlush = 3; 1647 1648 private int _writeState; 1649 private Buffer _writeBuffer; 1650 private int _writeBufferSize; 1651 private byte[] _writeMask; 1652 private int _writePayloadLength; 1653 1654 private bool _closingInitiator; 1655 private int _closingReason; 1656 1657 private bool _readPending; 1658 private bool _finishRead; 1659 private bool _writePending; 1660 1661 private byte[] _pingPayload; 1662 1663 private Random _rand; 1664 1665 // 1666 // WebSocket opcodes 1667 // 1668 private const int OP_CONT = 0x0; // Continuation frame 1669 private const int OP_TEXT = 0x1; // Text frame 1670 private const int OP_DATA = 0x2; // Data frame 1671 private const int OP_RES_0x3 = 0x3; // Reserved 1672 private const int OP_RES_0x4 = 0x4; // Reserved 1673 private const int OP_RES_0x5 = 0x5; // Reserved 1674 private const int OP_RES_0x6 = 0x6; // Reserved 1675 private const int OP_RES_0x7 = 0x7; // Reserved 1676 private const int OP_CLOSE = 0x8; // Connection close 1677 private const int OP_PING = 0x9; // Ping 1678 private const int OP_PONG = 0xA; // Pong 1679 private const int OP_RES_0xB = 0xB; // Reserved 1680 private const int OP_RES_0xC = 0xC; // Reserved 1681 private const int OP_RES_0xD = 0xD; // Reserved 1682 private const int OP_RES_0xE = 0xE; // Reserved 1683 private const int OP_RES_0xF = 0xF; // Reserved 1684 private const int FLAG_FINAL = 0x80; // Last frame 1685 private const int FLAG_MASKED = 0x80; // Payload is masked 1686 1687 private const int CLOSURE_NORMAL = 1000; 1688 private const int CLOSURE_SHUTDOWN = 1001; 1689 private const int CLOSURE_PROTOCOL_ERROR = 1002; 1690 private const int CLOSURE_TOO_BIG = 1009; 1691 1692 private const string _iceProtocol = "ice.zeroc.com"; 1693 private const string _wsUUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 1694 1695 private static UTF8Encoding _utf8 = new UTF8Encoding(false, true); 1696 } 1697 } 1698