/// <summary> /// Synchronously send passed stream data using RV Protocol Version 1 /// </summary> /// <param name="username"></param> /// <param name="password"></param> /// <param name="streamData"></param> /// <returns>Whether data was sent and accepted by server. This will be false on /// connection error, invalid packet content or authorization failure. </returns> /// <remarks>Before calling this method Connect() and Handshake() should be called first. /// After data is sent connection is closed.</remarks> public bool sendStreamDataV1(string username, string password, StreamDataV1[] streamData) { Socket clientSocket = this.Connect(); SslStream clientSslStream = this.Handshake(clientSocket); try { byte[] buffer = new byte[RVProtocolV1PacketHandler.PacketSizeConst]; byte[] packet = RVProtocolV1PacketHandler.GetHello(); clientSslStream.Write(packet); clientSslStream.Read(buffer, 0, RVProtocolV1PacketHandler.PacketSizeConst); RVProtocolV1PacketHandler.ParseWelcome(buffer); packet = RVProtocolV1PacketHandler.GetChallengePlease(username, streamData); clientSslStream.Write(packet); clientSslStream.Read(buffer, 0, RVProtocolV1PacketHandler.PacketSizeConst); byte[] challengeWord = RVProtocolV1PacketHandler.ParseChallengeIs(buffer); packet = RVProtocolV1PacketHandler.GetChallengeResponse(RVProtocolV1PacketHandler.GenerateChallengeResponseHash(challengeWord, password)); clientSslStream.Write(packet); clientSslStream.Read(buffer, 0, RVProtocolV1PacketHandler.PacketSizeConst); bool result = RVProtocolV1PacketHandler.ParseChallengePassOrFail(buffer); packet = RVProtocolV1PacketHandler.GetBye(); clientSslStream.Write(packet); clientSslStream.Close(); clientSocket.Close(); return result; } catch(Exception e) { clientSslStream.Close(); clientSocket.Close(); throw new Exception("Error during socket communication.", e); } }
/// <summary> /// Generate CHALLENGE_PLEASE packet /// </summary> /// <param name="username"></param> /// <param name="password"></param> /// <param name="streamData"></param> /// <returns>Array of bytes ready to send via network</returns> /// <remarks>As the maximum lenght of a packet is limited it may happen that /// too big streamData won't fit inside. If it happens some of the stream data /// may not be included in the generated packet. Hovewer the returned array /// of bytes is guaranteed to contain a valid RVProtocolV1 packet in that case. /// The excluded part of the streamData WILL NOT be put into the returned array partially /// and WILL NOT invalidate the packet. /// /// A workaround to this would be to split streamData and prepare many packets instead /// of one.</remarks> public static byte[] GetChallengePlease(string username, StreamDataV1[] streamData) { string packetData = DataKeyStrings[DataKey.User] + DataKeyStrings[DataKey.Separator] + username + DataKeyStrings[DataKey.Separator]; foreach (StreamDataV1 s in streamData) { string currentStreamData = DataKeyStrings[DataKey.Stream] + DataKeyStrings[DataKey.Separator] + s.streamName + DataKeyStrings[DataKey.Separator] + DataKeyStrings[DataKey.Port] + DataKeyStrings[DataKey.Separator] + s.port + DataKeyStrings[DataKey.Separator] + DataKeyStrings[DataKey.ProxiedName] + DataKeyStrings[DataKey.Separator] + s.proxiedName + DataKeyStrings[DataKey.Separator]; //check if there is still enough space in the packet to add more data if (currentStreamData.Length + 1 <= PacketSizeConst - packetData.Length) { packetData += currentStreamData; } else { break; } } // remove the trailing ':' from the end of string return Combine(MessageCode.ChallengePlease, packetData.Substring(0, packetData.Length - 1)); }