public bool TryHandshake(Connection conn, Uri uri) { try { Stream stream = conn.stream; byte[] keyBuffer = new byte[16]; using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) { rng.GetBytes(keyBuffer); } string key = Convert.ToBase64String(keyBuffer); string keySum = key + Constants.HandshakeGUID; byte[] keySumBytes = Encoding.ASCII.GetBytes(keySum); Log.Verbose($"Handshake Hashing {Encoding.ASCII.GetString(keySumBytes)}"); byte[] keySumHash = SHA1.Create().ComputeHash(keySumBytes); string expectedResponse = Convert.ToBase64String(keySumHash); string handshake = $"GET /chat HTTP/1.1\r\n" + $"Host: {uri.Host}:{uri.Port}\r\n" + $"Upgrade: websocket\r\n" + $"Connection: Upgrade\r\n" + $"Sec-WebSocket-Key: {key}\r\n" + $"Sec-WebSocket-Version: 13\r\n" + "\r\n"; byte[] encoded = Encoding.ASCII.GetBytes(handshake); stream.Write(encoded, 0, encoded.Length); byte[] responseBuffer = new byte[1000]; int?lengthOrNull = ReadHelper.SafeReadTillMatch(stream, responseBuffer, 0, responseBuffer.Length, Constants.endOfHandshake); if (!lengthOrNull.HasValue) { Log.Error("Connected closed before handshake"); return(false); } string responseString = Encoding.ASCII.GetString(responseBuffer, 0, lengthOrNull.Value); string acceptHeader = "Sec-WebSocket-Accept: "; int startIndex = responseString.IndexOf(acceptHeader) + acceptHeader.Length; int endIndex = responseString.IndexOf("\r\n", startIndex); string responseKey = responseString.Substring(startIndex, endIndex - startIndex); if (responseKey != expectedResponse) { Log.Error($"Response key incorrect, Response:{responseKey} Expected:{expectedResponse}"); return(false); } return(true); } catch (Exception e) { Log.Exception(e); return(false); } }
string ReadToEndForHandshake(Stream stream) { using (ArrayBuffer readBuffer = bufferPool.Take(maxHttpHeaderSize)) { int?readCountOrFail = ReadHelper.SafeReadTillMatch(stream, readBuffer.array, 0, maxHttpHeaderSize, Constants.endOfHandshake); if (!readCountOrFail.HasValue) { return(null); } int readCount = readCountOrFail.Value; string msg = Encoding.ASCII.GetString(readBuffer.array, 0, readCount); Log.Verbose(msg); return(msg); } }