示例#1
0
        private bool ShakeHands()
        {
            _Header["Version"] = "0";

            try
            {
                // Peek first byte for 22, 128 (indicates ssl)
                // Don't use class methods for peek/read since they eat data into the input buffer, and AuthenticateAsServer needs that data
                if (_Socket.Poll(5 * 1000 * 1000, SelectMode.SelectRead))
                {
                    byte[] FirstByte = new byte[1];
                    _Socket.Receive(FirstByte, 0, 1, SocketFlags.Peek);
                    if ((FirstByte[0] == 22) || (FirstByte[0] == 128))
                    {
                        if (_Certificate == null)
                        {
                            throw new Exception("wss:// requires a certificate");
                        }
                        else
                        {
                            var SSL = new SslStream(_Stream, false);
                            _Stream = SSL;
                            SSL.AuthenticateAsServer(_Certificate, false, SslProtocols.Tls, false);
                            Protocol = "wss";
                        }
                    }
                }
                else
                {
                    RMLog.Error("Timeout exceeded while waiting for complete handshake");
                    return(false);
                }

                // Keep reading header data until we get all the data we want
                while (true)
                {
                    // Read another line, and abort if we don't get one within 5 seconds
                    string InLine = ReadLn(new string[] { "\r\n", "\0" }, false, '\0', 5000).Trim();
                    if (ReadTimedOut)
                    {
                        RMLog.Error("Timeout exceeded while waiting for complete handshake");
                        return(false);
                    }

                    RMLog.Trace("Handshake Line: " + InLine);

                    // Check for blank line (indicates we have most of the header, and only the last 8 bytes remain
                    if (string.IsNullOrEmpty(InLine))
                    {
                        switch (_Header["Version"])
                        {
                        case "0":
                            if (_Header.ContainsKey("Sec-WebSocket-Key1"))
                            {
                                _ProtocolVersion = ProtocolVersion.Hixie76;
                                return(ShakeHandsHixie76());
                            }
                            else
                            {
                                // Only used by Chrome 4 and iOS 5.0.0 so probably not worth bothering
                                _ProtocolVersion = ProtocolVersion.Hixie75;
                                return(false);
                            }

                        case "7":
                        case "8":
                        case "13":
                            _ProtocolVersion = ProtocolVersion.RFC6455;
                            return(ShakeHandsRFC6455());

                        default:
                            //		    TODO If this version does not
                            //          match a version understood by the server, the server MUST
                            //          abort the websocket handshake described in this section and
                            //          instead send an appropriate HTTP error code (such as 426
                            //          Upgrade Required), and a |Sec-WebSocket-Version| header
                            //          indicating the version(s) the server is capable of
                            //          understanding.
                            return(false);
                        }
                        break;
                    }
                    else if (InLine.StartsWith("Connection:"))
                    {
                        // Example: "Connection: Upgrade"
                        // NB: New in protocol 8+
                        _Header["Connection"] = InLine.Replace("Connection:", "").Trim();
                    }
                    else if (InLine.StartsWith("GET"))
                    {
                        // Example: "GET /demo HTTP/1.1"
                        string[] GET = InLine.Split(' ');
                        _Header["Path"] = GET[1];
                    }
                    else if (InLine.StartsWith("Host:"))
                    {
                        // Example: "Host: example.com"
                        _Header["Host"] = InLine.Replace("Host:", "").Trim();
                    }
                    else if (InLine.StartsWith("Origin:"))
                    {
                        // Example: "Origin: http://example.com"
                        // NB: Not used in protocol 8+
                        _Header["Origin"] = InLine.Replace("Origin:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key:"))
                    {
                        // Example: "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="
                        // NB: New in protocol 8+
                        _Header["Key"] = InLine.Replace("Sec-WebSocket-Key:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key1:"))
                    {
                        // Example: "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5"
                        // NB: Not used in protocol 8+
                        _Header["Key1"] = InLine.Replace("Sec-WebSocket-Key1:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key2:"))
                    {
                        // Example: "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00"
                        // NB: Not used in protocol 8+
                        _Header["Key2"] = InLine.Replace("Sec-WebSocket-Key2:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Origin:"))
                    {
                        // Example: "Sec-WebSocket-Origin: http://example.com"
                        // NB: New in protocol 8+
                        _Header["Origin"] = InLine.Replace("Sec-WebSocket-Origin:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Protocol:"))
                    {
                        // Example: "Sec-WebSocket-Protocol: sample"
                        _Header["SubProtocol"] = InLine.Replace("Sec-WebSocket-Protocol:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Draft"))
                    {
                        // Example: "Sec-WebSocket-Draft: 2"
                        _Header["Version"] = InLine.Replace("Sec-WebSocket-Draft:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Version"))
                    {
                        // Example: "Sec-WebSocket-Version: 8"
                        _Header["Version"] = InLine.Replace("Sec-WebSocket-Version:", "").Trim();
                    }
                    else if (InLine.StartsWith("Upgrade:"))
                    {
                        // Example: "Upgrade: websocket"
                        // NB: New in protocol 8+
                        _Header["Upgrade"] = InLine.Replace("Upgrade:", "").Trim();
                    }
                    else if (InLine.StartsWith("<policy-file-request"))
                    {
                        string PolicyResponse =
                            "<?xml version=\"1.0\"?>\n" +
                            "<cross-domain-policy>\n" +
                            "   <allow-access-from domain=\"*\" to-ports=\"*\"/>\n" +
                            "   <site-control permitted-cross-domain-policies=\"all\"/>\n" +
                            "</cross-domain-policy>\n" +
                            "\0";
                        WriteRaw(Encoding.UTF8.GetBytes(PolicyResponse));
                        FlashPolicyFileRequest = true;
                        return(false);
                    }
                }
            }
            catch (Exception ex)
            {
                RMLog.Exception(ex, "Exception in WebSocketConnection::ShakeHands()");
            }

            return(false);
        }