protected override Task <SendPingReply> SendPingImplAsync(IPAddress target, byte[] data, int timeout, CancellationToken cancel)
 {
     // 現時点で SendAsync メソッドはキャンセルや厳密なタイムアウトを実現していないので DoAsyncWithTimeout() を用いて無理矢理実現する
     return(TaskUtil.DoAsyncWithTimeout((c) =>
     {
         return Legacy.SendPing.SendAsync(target, data, timeout);
     }, timeout: timeout + 1000, cancel: cancel));
 }
Пример #2
0
        public async Task StartWebSocketClientAsync(string uri, CancellationToken cancel = default)
        {
            if (Started.IsFirstCall() == false)
            {
                throw new ApplicationException("Already started.");
            }

            LowerStream.ReadTimeout  = Options.TimeoutOpen;
            LowerStream.WriteTimeout = Options.TimeoutOpen;

            Uri u = new Uri(uri);
            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, uri);

            byte[] nonce      = Secure.Rand(16);
            string requestKey = Convert.ToBase64String(nonce);

            req.Headers.Add("Host", u.Host);
            req.Headers.Add("User-Agent", Options.UserAgent);
            req.Headers.Add("Accept", Consts.MimeTypes.Html);
            req.Headers.Add("Sec-WebSocket-Version", "13");
            req.Headers.Add("Origin", "null");
            req.Headers.Add("Sec-WebSocket-Key", requestKey);
            req.Headers.Add("Connection", "keep-alive, Upgrade");
            req.Headers.Add("Pragma", "no-cache");
            req.Headers.Add("Cache-Control", "no-cache");
            req.Headers.Add("Upgrade", "websocket");

            StringWriter tmpWriter = new StringWriter();

            tmpWriter.WriteLine($"{req.Method} {req.RequestUri.PathAndQuery} HTTP/1.1");
            tmpWriter.WriteLine(req.Headers.ToString());

            await LowerStream.WriteAsync(tmpWriter.ToString()._GetBytes_UTF8(), cancel);

            Dictionary <string, string> headers = new Dictionary <string, string>(StrComparer.IgnoreCaseComparer);
            int num          = 0;
            int responseCode = 0;

            StreamReader tmpReader = new StreamReader(LowerStream);

            while (true)
            {
                string line = await TaskUtil.DoAsyncWithTimeout((procCancel) => tmpReader.ReadLineAsync(),
                                                                timeout : Options.TimeoutOpen,
                                                                cancel : cancel);

                if (line == "")
                {
                    break;
                }

                if (num == 0)
                {
                    string[] tokens = line.Split(' ');
                    if (tokens[0] != "HTTP/1.1")
                    {
                        throw new ApplicationException($"Cannot establish the WebSocket Protocol. Response: \"{tokens}\"");
                    }
                    responseCode = int.Parse(tokens[1]);
                }
                else
                {
                    string[] tokens = line.Split(':');
                    string   name   = tokens[0].Trim();
                    string   value  = tokens[1].Trim();
                    headers[name] = value;
                }

                num++;
            }

            if (responseCode != 101)
            {
                throw new ApplicationException($"Cannot establish the WebSocket Protocol. Perhaps the destination host does not support WebSocket. Wrong response code: \"{responseCode}\"");
            }

            if (headers["Upgrade"].Equals("websocket", StringComparison.InvariantCultureIgnoreCase) == false)
            {
                throw new ApplicationException($"Wrong Upgrade header: \"{headers["Upgrade"]}\"");
            }

            string acceptKey  = headers["Sec-WebSocket-Accept"];
            string keyCalcStr = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            SHA1   sha1       = new SHA1Managed();
            string acceptKey2 = Convert.ToBase64String(sha1.ComputeHash(keyCalcStr._GetBytes_Ascii()));

            if (acceptKey != acceptKey2)
            {
                throw new ApplicationException($"Wrong accept_key: \'{acceptKey}\'");
            }

            this.SendTask = SendLoopAsync();
            this.RecvTask = RecvLoopAsync();
        }