Ejemplo n.º 1
0
        private async Task ConnectClientInternal()
        {
            if (_socket != null)
            {
                throw new Exception("connect() is already called");
            }
            try
            {
                int    port = (_uri.Port != -1) ? _uri.Port : (_uri.Scheme.Equals("wss") ? 443 : 80);
                string path = (_uri.AbsolutePath != null) ? _uri.AbsolutePath : "/";
                if (_uri.Query != null)
                {
                    path += "?" + _uri.Query;
                }
                string originScheme = _uri.Scheme.Equals("wss") ? "https" : "http";
                Uri    origin       = new Uri(originScheme + "://" + _uri.Host);
                // To fix: get Origin from extraHeaders if set there.
                this._socket = new InternalSocket();
                await this._socket.ConnectAsync(_uri.Host, port);

                if (_uri.Scheme.Equals("wss"))
                {
                    await this._socket.UpgradeToSslAsync(_uri.Host);
                }
                string     key    = WebSocketHelper.CreateClientKey();
                DataWriter writer = new DataWriter(_socket.OutputStream);
                writer.WriteString("GET " + path + " HTTP/1.1\r\n");
                writer.WriteString("Upgrade: websocket\r\n");
                writer.WriteString("Connection: Upgrade\r\n");
                writer.WriteString("Host: " + _uri.Host + "\r\n");
                writer.WriteString("Origin: " + origin.ToString() + "\r\n");
                writer.WriteString("Sec-WebSocket-Key: " + key + "\r\n");
                writer.WriteString("Sec-WebSocket-Version: 13\r\n");
                if (_extraRequestHeaders != null)
                {
                    foreach (Http.Header header in _extraRequestHeaders)
                    {
                        writer.WriteString(header.ToString() + "\r\n");
                    }
                }
                writer.WriteString("\r\n");
                await writer.StoreAsync(); //异步发送数据

                writer.DetachStream();     //分离
                writer.Dispose();          //结束writer
                DataReader reader = new DataReader(_socket.InputStream);
                reader.ByteOrder = ByteOrder.LittleEndian;
                //// Read HTTP response status line.
                var startLine = await ReadLine(reader);

                if (startLine == null)
                {
                    throw new Exception("Received no reply from server.");
                }
                Http.StatusLine statusLine = new Http.StatusLine(startLine);
                int             statusCode = statusLine.StatusCode;
                if (statusCode != 101)
                {
                    throw new Exception("wrong HTTP response code: " + statusCode);
                }

                // Read HTTP response headers.
                string line;
                while ((line = await ReadLine(reader)) != null && line.Length > 0)
                {
                    Http.Header header = new Http.Header(line);
                    Debug.WriteLine(line);

                    if (header.HeaderName.Equals("Sec-WebSocket-Accept", StringComparison.OrdinalIgnoreCase))
                    {
                        string receivedAccept = header.HeaderValue;
                        string shouldBeAccept = WebSocketHelper.CreateAccept(key);
                        if (!receivedAccept.Equals(shouldBeAccept))
                        {
                            throw new Exception("Wrong Sec-WebSocket-Accept: " + receivedAccept + " should be: " + shouldBeAccept);
                        }
                    }
                    if (_serverResponseHeaders == null)
                    {
                        _serverResponseHeaders = new List <Http.Header>();
                    }
                    _serverResponseHeaders.Add(header);
                }
                if (this.Opened != null)
                {
                    this.Opened(this, EventArgs.Empty);
                }
                //Upgrade: websocket
                //Connection: Upgrade
                //Sec-WebSocket-Accept: 1xY289lHcEMbLpEBgOYRBBL9N9c=
                //Sec-WebSocket-Protocol: chat
                //Content-Type: application/octet-stream
                //Seq-Id: 667035124
                // Read & process frame
                while (true)
                {
                    FrameParser.Frame frame = await FrameParser.ReadFrame(reader);

                    if (frame != null)
                    {
                        await ProcessIncomingFrame(frame);
                    }
                }
            }
            catch (IOException ex)
            {
                if (this.Closed != null)
                {
                    this.Closed(this, new WebSocketClosedEventArgs(0, "EOF"));
                }
            }
            catch (Exception ex)
            {
                if (this.Closed != null)
                {
                    this.Closed(this, new WebSocketClosedEventArgs(0, ex.Message));
                }
            }
            finally
            {
                Disconnect();
            }
        }
Ejemplo n.º 2
0
        private async Task ProcessIncomingFrame(FrameParser.Frame frame)
        {
            switch (frame.opCode)
            {
            case FrameParser.OP_CONTINUATION:
                await _stream.WriteAsync(frame.payload?.ToBuffer());

                if (frame.isFinal)
                {
                    var    buffer  = _stream.ToBuffer();
                    byte[] message = buffer.ToByteArray();
                    if (this.OnMessage != null)
                    {
                        this.OnMessage(this, new WebSocketMessageEventArgs(this.Control.MessageType, message));
                    }
                    this.ResetStream();
                }
                break;

            case FrameParser.OP_TEXT:
                if (frame.isFinal)
                {
                    if (this.OnMessage != null)
                    {
                        this.OnMessage(this, new WebSocketMessageEventArgs(this.Control.MessageType, frame.payload));
                    }
                }
                else
                {
                    if (_stream.Size != 0)
                    {
                        throw new IOException("no FIN frame");
                    }
                    this.Control.MessageType = WebSocketMessageType.Text;
                    await _stream.WriteAsync(frame.payload.ToBuffer());
                }
                break;

            case FrameParser.OP_BINARY:
                if (frame.isFinal)
                {
                    if (this.OnMessage != null)
                    {
                        this.OnMessage(this, new WebSocketMessageEventArgs(this.Control.MessageType, frame.payload));
                    }
                }
                else
                {
                    if (_stream.Size != 0)
                    {
                        throw new IOException("no FIN frame");
                    }
                    this.Control.MessageType = WebSocketMessageType.Binary;
                    await _stream.WriteAsync(frame.payload.ToBuffer());
                }
                break;

            case FrameParser.OP_CLOSE:
                int code = 0;
                if (frame.payload.Length >= 2)
                {
                    code = ((frame.payload[0] << 8) | (frame.payload[1] & 0xFF)) & 0xFFFF;
                }
                string reason = null;
                if (frame.payload.Length > 2)
                {
                    var temp = frame.payload.CopyOfRange(2, frame.payload.Length);
                    reason = Encoding.UTF8.GetString(temp, 0, temp.Length);
                }
                if (this.Closed != null)
                {
                    this.Closed(this, new WebSocketClosedEventArgs(code, reason));
                }
                this.Disconnect();
                break;

            case FrameParser.OP_PING:
                if (frame.payload.Length > 125)
                {
                    throw new IOException("Ping payload too large");
                }
                byte[] data = FrameParser.BuildFrame(frame.payload, FrameParser.OP_PONG, -1, IS_CLIENT, true);
                await SendFrame(data);

                break;

            case FrameParser.OP_PONG:
                if (this.OnPong != null)
                {
                    this.OnPong(this, frame.payload);
                }
                break;
            }
        }
Ejemplo n.º 3
0
        private void ConnectServer()
        {
            Task.Factory.StartNew(async() =>
            {
                try
                {
                    DataReader stream = new DataReader(this._socket.InputStream);

                    // Read HTTP request line.
                    string startLine = await this.ReadLine(stream);
                    if (startLine == null)
                    {
                        throw new Exception("Cannot read HTTP request start line");
                    }

                    Http.RequestLine requestLine = new Http.RequestLine(startLine);
                    this._uri = new Uri(requestLine.RequestURI); // can be checked in
                    // onConnect()

                    // Read HTTP response headers
                    Dictionary <string, string> map = new Dictionary <string, string>();
                    string line;
                    while ((line = await this.ReadLine(stream)) != null && line.Length > 0)
                    {
                        Http.Header header = new Http.Header(line);
                        map.Add(header.HeaderName.ToLower(), header.HeaderValue);
                    }

                    string value = map["sec-websocket-version"];
                    if (!"13".Equals(value))
                    {
                        throw new IOException("wrong Sec-WebSocket-Version");
                    }

                    string key = map["sec-websocket-key"];
                    if (key == null)
                    {
                        throw new IOException("missed Sec-WebSocket-Key");
                    }
                    string accept = WebSocketHelper.CreateAccept(key);

                    string upgrade = map["upgrade"];
                    if (upgrade == null || !upgrade.Equals("websocket", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new IOException("wrong Upgrade");
                    }

                    string connection = map["connection"];
                    if (connection == null || !connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new IOException("wrong Connection");
                    }

                    // Host and Origin can be checked later in onConnect() callback.
                    this._host = map["host"];
                    if (this._host == null)
                    {
                        throw new IOException("Missed 'Host' header");
                    }

                    this._origin = map["origin"];
                    if (this._origin == null)
                    {
                        throw new IOException("Missed 'Origin' header");
                    }

                    // Some naive protocol selection.
                    string protocols        = map["sec-websocket-protocol"];
                    string selectedProtocol = null;
                    if (protocols != null && protocols.Contains("chat"))
                    {
                        selectedProtocol = "chat";
                    }

                    DataWriter writer = new DataWriter(this._socket.OutputStream);
                    writer.WriteString("HTTP/1.1 101 Switching Protocols\r\n");
                    writer.WriteString("Upgrade: websocket\r\n");
                    writer.WriteString("Connection: Upgrade\r\n");
                    writer.WriteString("Sec-WebSocket-Accept: " + accept + "\r\n");
                    if (selectedProtocol != null)
                    {
                        writer.WriteString("Sec-WebSocket-Protocol: " + selectedProtocol + "\r\n");
                    }
                    writer.WriteString("\r\n");
                    await writer.FlushAsync();

                    if (this.Opened != null)
                    {
                        this.Opened(this, EventArgs.Empty);
                    }

                    // Read & process frame
                    for (;;)
                    {
                        FrameParser.Frame frame = await FrameParser.ReadFrame(stream);
                        await this.ProcessIncomingFrame(frame);
                    }
                }
                catch (IOException ex)
                {
                    if (this.Closed != null)
                    {
                        this.Closed(this, new WebSocketClosedEventArgs(0, "EOF"));
                    }
                }
                catch (Exception ex)
                {
                    if (this.Closed != null)
                    {
                        this.Closed(this, new WebSocketClosedEventArgs(0, "Exception"));
                    }
                }
                finally
                {
                    this.Disconnect();
                }
            });
        }