예제 #1
0
		public async Task Send(MTProtoRequest request)
		{
			// TODO: refactor
			if (needConfirmation.Any())
			{
				var ackRequest = new AckRequest(needConfirmation);
				using (var memory = new MemoryStream())
				using (var writer = new BinaryWriter(memory))
				{
					ackRequest.OnSend(writer);
					await Send(memory.ToArray(), ackRequest);
					needConfirmation.Clear();
				}
			}
			

			using (var memory = new MemoryStream())
			using (var writer = new BinaryWriter(memory))
			{
				request.OnSend(writer);
				await Send(memory.ToArray(), request);
			}

			_session.Save();
		}
예제 #2
0
		public async Task Send(byte[] packet, MTProtoRequest request)
		{
			request.MessageId = _session.GetNewMessageId();
		
			byte[] msgKey;
			byte[] ciphertext;
			using (MemoryStream plaintextPacket = makeMemory(8 + 8 + 8 + 4 + 4 + packet.Length))
			{
				using (BinaryWriter plaintextWriter = new BinaryWriter(plaintextPacket))
				{
					plaintextWriter.Write(_session.Salt);
					plaintextWriter.Write(_session.Id);
					plaintextWriter.Write(request.MessageId);
					plaintextWriter.Write(GenerateSequence(request.Confirmed));
					plaintextWriter.Write(packet.Length);
					plaintextWriter.Write(packet);

					msgKey = Helpers.CalcMsgKey(plaintextPacket.GetBuffer());
					ciphertext = AES.EncryptAES(Helpers.CalcKey(_session.AuthKey.Data, msgKey, true), plaintextPacket.GetBuffer());
				}
			}

			using (MemoryStream ciphertextPacket = makeMemory(8 + 16 + ciphertext.Length))
			{
				using (BinaryWriter writer = new BinaryWriter(ciphertextPacket))
				{
					writer.Write(_session.AuthKey.Id);
					writer.Write(msgKey);
					writer.Write(ciphertext);

					await _transport.Send(ciphertextPacket.GetBuffer());
				}
			}
		}
예제 #3
0
		private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			uint code = messageReader.ReadUInt32();
			int size = messageReader.ReadInt32();
			for (int i = 0; i < size; i++)
			{
				ulong innerMessageId = messageReader.ReadUInt64();
				int innerSequence = messageReader.ReadInt32();
				int innerLength = messageReader.ReadInt32();
				long beginPosition = messageReader.BaseStream.Position;
				try
				{
					if (!processMessage(innerMessageId, sequence, messageReader, request))
					{
						messageReader.BaseStream.Position = beginPosition + innerLength;
					}
				}
				catch (Exception e)
				{
					//	logger.error("failed to process message in contailer: {0}", e);
					messageReader.BaseStream.Position = beginPosition + innerLength;
				}
			}

			return false;
		}
예제 #4
0
		private bool HandleBadServerSalt(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			uint code = messageReader.ReadUInt32();
			ulong badMsgId = messageReader.ReadUInt64();
			int badMsgSeqNo = messageReader.ReadInt32();
			int errorCode = messageReader.ReadInt32();
			ulong newSalt = messageReader.ReadUInt64();

			//logger.debug("bad_server_salt: msgid {0}, seq {1}, errorcode {2}, newsalt {3}", badMsgId, badMsgSeqNo, errorCode, newSalt);

			_session.Salt = newSalt;

			//resend
			Send(request);
			/*
            if(!runningRequests.ContainsKey(badMsgId)) {
                logger.debug("bad server salt on unknown message");
                return true;
            }
            */


			//MTProtoRequest request = runningRequests[badMsgId];
			//request.OnException(new MTProtoBadServerSaltException(salt));

			return true;
		}
예제 #5
0
		private bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			uint code = messageReader.ReadUInt32();
			ulong requestId = messageReader.ReadUInt64();

			if (requestId == (ulong) request.MessageId)
				request.ConfirmReceived = true;

			//throw new NotImplementedException();
			/*
			lock (runningRequests)
			{
				if (!runningRequests.ContainsKey(requestId))
				{
					logger.warning("rpc response on unknown request: {0}", requestId);
					messageReader.BaseStream.Position -= 12;
					return false;
				}

				request = runningRequests[requestId];
				runningRequests.Remove(requestId);
			}
			*/

			uint innerCode = messageReader.ReadUInt32();
			if (innerCode == 0x2144ca19)
			{ // rpc_error
				int errorCode = messageReader.ReadInt32();
				string errorMessage = Serializers.String.read(messageReader);

				if (errorMessage.StartsWith("FLOOD_WAIT_"))
				{
					var resultString = Regex.Match(errorMessage, @"\d+").Value;
					var seconds = int.Parse(resultString);
					Debug.WriteLine($"Should wait {seconds} sec.");
					Thread.Sleep(1000*seconds);
				}
				else if (errorMessage.StartsWith("PHONE_MIGRATE_"))
				{
					var resultString = Regex.Match(errorMessage, @"\d+").Value;
					var dcIdx = int.Parse(resultString);
					var exception = new InvalidOperationException($"Your phone number registered to {dcIdx} dc. Please update settings. See https://github.com/sochix/TLSharp#i-get-an-error-migrate_x for details.");
					exception.Data.Add("dcId", dcIdx);
					throw exception;
				}
				else
				{
					throw new InvalidOperationException(errorMessage);
				}
				
			}
			else if (innerCode == 0x3072cfa1)
			{
				try
				{
					// gzip_packed
					byte[] packedData = Serializers.Bytes.read(messageReader);
					using (var packedStream = new MemoryStream(packedData, false))
					using (var zipStream = new GZipStream(packedStream, CompressionMode.Decompress))
					using (var compressedReader = new BinaryReader(zipStream))
					{
						request.OnResponse(compressedReader);
					}
				}
				catch (ZlibException ex)
				{
					
				}
			}
			else
			{
				messageReader.BaseStream.Position -= 4;

				request.OnResponse(messageReader);
			}

			return false;
		}
예제 #6
0
		private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			uint code = messageReader.ReadUInt32();
			byte[] packedData = GZipStream.UncompressBuffer(Serializers.Bytes.read(messageReader));
			using (MemoryStream packedStream = new MemoryStream(packedData, false))
			using (BinaryReader compressedReader = new BinaryReader(packedStream))
			{
				processMessage(messageId, sequence, compressedReader, request);
			}

			return true;
		}
예제 #7
0
		private bool processMessage(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			// TODO: check salt
			// TODO: check sessionid
			// TODO: check seqno

			//logger.debug("processMessage: msg_id {0}, sequence {1}, data {2}", BitConverter.ToString(((MemoryStream)messageReader.BaseStream).GetBuffer(), (int) messageReader.BaseStream.Position, (int) (messageReader.BaseStream.Length - messageReader.BaseStream.Position)).Replace("-","").ToLower());
			needConfirmation.Add(messageId);
			
			uint code = messageReader.ReadUInt32();
			messageReader.BaseStream.Position -= 4;
			switch (code)
			{
				case 0x73f1f8dc: // container
								 //logger.debug("MSG container");
					return HandleContainer(messageId, sequence, messageReader, request);
				case 0x7abe77ec: // ping
								 //logger.debug("MSG ping");
					return HandlePing(messageId, sequence, messageReader);
				case 0x347773c5: // pong
								 //logger.debug("MSG pong");
					return HandlePong(messageId, sequence, messageReader);
				case 0xae500895: // future_salts
								 //logger.debug("MSG future_salts");
					return HandleFutureSalts(messageId, sequence, messageReader);
				case 0x9ec20908: // new_session_created
								 //logger.debug("MSG new_session_created");
					return HandleNewSessionCreated(messageId, sequence, messageReader);
				case 0x62d6b459: // msgs_ack
								 //logger.debug("MSG msds_ack");
					return HandleMsgsAck(messageId, sequence, messageReader);
				case 0xedab447b: // bad_server_salt
								 //logger.debug("MSG bad_server_salt");
					return HandleBadServerSalt(messageId, sequence, messageReader, request);
				case 0xa7eff811: // bad_msg_notification
								 //logger.debug("MSG bad_msg_notification");
					return HandleBadMsgNotification(messageId, sequence, messageReader);
				case 0x276d3ec6: // msg_detailed_info
								 //logger.debug("MSG msg_detailed_info");
					return HandleMsgDetailedInfo(messageId, sequence, messageReader);
				case 0xf35c6d01: // rpc_result
								 //logger.debug("MSG rpc_result");
					return HandleRpcResult(messageId, sequence, messageReader, request);
				case 0x3072cfa1: // gzip_packed
								 //logger.debug("MSG gzip_packed");
					return HandleGzipPacked(messageId, sequence, messageReader, request);
				case 0xe317af7e:
				case 0xd3f45784:
				case 0x2b2fbd4e:
				case 0x78d4dec1:
				case 0x725b04c3:
				case 0x74ae4240:
					return HandleUpdate(messageId, sequence, messageReader);
				default:
					//logger.debug("unknown message: {0}", code);
					return false;
			}
		}
예제 #8
0
		public async Task<byte[]> Recieve(MTProtoRequest request)
		{
			while (!request.ConfirmReceived)
			{
				var result = DecodeMessage((await _transport.Receieve()).Body);

				using (var messageStream = new MemoryStream(result.Item1, false))
				using (var messageReader = new BinaryReader(messageStream))
				{
					processMessage(result.Item2, result.Item3, messageReader, request);
				}
			}

			return null;
		}
예제 #9
0
		private bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
		{
			uint code = messageReader.ReadUInt32();
			ulong requestId = messageReader.ReadUInt64();

			if (requestId == (ulong) request.MessageId)
				request.ConfirmReceived = true;

			//throw new NotImplementedException();
			/*
			lock (runningRequests)
			{
				if (!runningRequests.ContainsKey(requestId))
				{
					logger.warning("rpc response on unknown request: {0}", requestId);
					messageReader.BaseStream.Position -= 12;
					return false;
				}

				request = runningRequests[requestId];
				runningRequests.Remove(requestId);
			}
			*/

			uint innerCode = messageReader.ReadUInt32();
			if (innerCode == 0x2144ca19)
			{ // rpc_error
				int errorCode = messageReader.ReadInt32();
				string errorMessage = Serializers.String.read(messageReader);

				if (errorMessage.StartsWith("FLOOD_WAIT_"))
				{
					var resultString = Regex.Match(errorMessage, @"\d+").Value;
					var seconds = int.Parse(resultString);
					Debug.WriteLine($"Should wait {seconds} sec.");
					Thread.Sleep(1000*seconds);
				}
				else
				{
					throw new InvalidOperationException(errorMessage);
				}
				
			}
			else if (innerCode == 0x3072cfa1)
			{
				// gzip_packed
				byte[] packedData = Serializers.Bytes.read(messageReader);
				using (MemoryStream packedStream = new MemoryStream(packedData, false))
				using (GZipStream zipStream = new GZipStream(packedStream, CompressionMode.Decompress))
				using (BinaryReader compressedReader = new BinaryReader(zipStream))
				{
					request.OnResponse(compressedReader);
				}
			}
			else
			{
				messageReader.BaseStream.Position -= 4;

				request.OnResponse(messageReader);
			}

			return false;
		}