Exemple #1
0
        public static TcpMessage Decode(byte[] body)
        {
            if (body == null)
                throw new ArgumentNullException(nameof(body));

            if (body.Length < 12)
                throw new InvalidOperationException("Ops, wrong size of input packet");

            using (var memoryStream = new MemoryStream(body))
            {
                using (var binaryReader = new BinaryReader(memoryStream))
                {
                    var packetLength = binaryReader.ReadInt32();

                    if (packetLength < 12)
                        throw new InvalidOperationException(string.Format("invalid packet length: {0}", packetLength));

                    var seq = binaryReader.ReadInt32();
                    byte[] packet = binaryReader.ReadBytes(packetLength - 12);
                    var checksum = (int)binaryReader.ReadInt32();

                    var crc32 = new CRC32();
                    crc32.SlurpBlock(body, 0, packetLength - 4);
                    var validChecksum = crc32.Crc32Result;

                    if (checksum != validChecksum)
                    {
                        throw new InvalidOperationException("invalid checksum! skip");
                    }

                    return new TcpMessage(seq, packet);
                }
            }
        }
Exemple #2
0
		public byte[] Encode()
		{
			using (var memoryStream = new MemoryStream())
			{
				using (var binaryWriter = new BinaryWriter(memoryStream))
				{
					// https://core.telegram.org/mtproto#tcp-transport
					/*
                        4 length bytes are added at the front 
                        (to include the length, the sequence number, and CRC32; always divisible by 4)
                        and 4 bytes with the packet sequence number within this TCP connection 
                        (the first packet sent is numbered 0, the next one 1, etc.),
                        and 4 CRC32 bytes at the end (length, sequence number, and payload together).
                    */
					binaryWriter.Write(Body.Length + 12);
					binaryWriter.Write(SequneceNumber);
					binaryWriter.Write(Body);
					var crc32 = new CRC32();
					crc32.SlurpBlock(memoryStream.GetBuffer(), 0, 8 + Body.Length);
					binaryWriter.Write(crc32.Crc32Result);

					var transportPacket = memoryStream.ToArray();

					//					Debug.WriteLine("Tcp packet #{0}\n{1}", SequneceNumber, BitConverter.ToString(transportPacket));

					return transportPacket;
				}
			}
		}
Exemple #3
0
        private static async Task <TcpMessage> Receieve(TcpClient tcpClient)
        {
            var stream = tcpClient.GetStream();

            var packetLengthBytes = new byte[4];

            if (await stream.ReadAsync(packetLengthBytes, 0, 4) != 4)
            {
                throw new InvalidOperationException("Couldn't read the packet length");
            }
            int packetLength = BitConverter.ToInt32(packetLengthBytes, 0);

            var seqBytes = new byte[4];

            if (await stream.ReadAsync(seqBytes, 0, 4) != 4)
            {
                throw new InvalidOperationException("Couldn't read the sequence");
            }
            int seq = BitConverter.ToInt32(seqBytes, 0);

            int readBytes    = 0;
            var body         = new byte[packetLength - 12];
            int neededToRead = packetLength - 12;

            do
            {
                var bodyByte       = new byte[packetLength - 12];
                var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead);

                neededToRead -= availableBytes;
                Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes);
                readBytes += availableBytes;
            }while (readBytes != packetLength - 12);

            var crcBytes = new byte[4];

            if (await stream.ReadAsync(crcBytes, 0, 4) != 4)
            {
                throw new InvalidOperationException("Couldn't read the crc");
            }
            int checksum = BitConverter.ToInt32(crcBytes, 0);

            byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length];

            Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length);
            Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length);
            Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length);
            var crc32 = new Ionic.Crc.CRC32();

            crc32.SlurpBlock(rv, 0, rv.Length);
            var validChecksum = crc32.Crc32Result;

            if (checksum != validChecksum)
            {
                throw new InvalidOperationException("invalid checksum! skip");
            }

            return(new TcpMessage(seq, body));
        }
 // This ctor is private - no validation is done here.  This is to allow the use
 // of a (specific) negative value for the _lengthLimit, to indicate that there
 // is no length set.  So we validate the length limit in those ctors that use an
 // explicit param, otherwise we don't validate, because it could be our special
 // value.
 private CrcCalculatorStream
     (bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
     : base()
 {
     _innerStream = stream;
     _Crc32 = crc32 ?? new CRC32();
     _lengthLimit = length;
     _leaveOpen = leaveOpen;
 }
 /// <summary>
 ///   A constructor allowing the specification of the length of the stream
 ///   to read, as well as whether to keep the underlying stream open upon
 ///   Close(), and the CRC32 instance to use.
 /// </summary>
 /// <remarks>
 ///   <para>
 ///     The stream uses the specified CRC32 instance, which allows the
 ///     application to specify how the CRC gets calculated.
 ///   </para>
 /// </remarks>
 /// <param name="stream">The underlying stream</param>
 /// <param name="length">The length of the stream to slurp</param>
 /// <param name="leaveOpen">true to leave the underlying stream
 /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
 /// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
 public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
                            CRC32 crc32)
     : this(leaveOpen, length, stream, crc32)
 {
     if (length < 0)
         throw new ArgumentException("length");
 }
 public int Crc32(int currentReadPositionOffset, int length) {
     //Crc32 crc32 = new Crc32();
     //logger.info("calc crc32 offset {0}, length {1} on: {2}", currentReadPositionOffset, length, BitConverter.ToString(buffer, readIndex + currentReadPositionOffset, length));
     //return crc32.ComputeHash(buffer, readIndex + currentReadPositionOffset, length).Reverse().ToArray();
     CRC32 crc32 = new CRC32();
     crc32.SlurpBlock(buffer, readIndex+currentReadPositionOffset, length);
     return crc32.Crc32Result;
 }
Exemple #7
0
 // This ctor is private - no validation except null is done here.
 // This is to allow the use
 // of a (specific) negative value for the _lengthLimit, to indicate that there
 // is no length set.  So we validate the length limit in those ctors that use an
 // explicit param, otherwise we don't validate, because it could be our special
 // value.
 CrcCalculatorStream(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
 {
     if (stream == null) throw new ArgumentNullException("stream");
     _innerStream = stream;
     _crc32 = crc32 ?? new CRC32();
     _lengthLimit = length;
     _leaveOpen = leaveOpen;
 }
        public async Task Send(byte[] packet) {
            AsyncSocket socketToSend;
            logger.debug("transport send...");
            lock (this) {
                if (socket == null) {
                    logger.debug("socket == null");
                    throw new MTProtoTransportException("not connected");
                }
                logger.debug("socket != null");
                socketToSend = socket;
            }

            try {
                using (MemoryStream memoryStream = new MemoryStream()) {
                    using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) {
                        CRC32 crc32 = new CRC32();
                        binaryWriter.Write(packet.Length + 12);
                        binaryWriter.Write(Interlocked.Increment(ref sendCounter) - 1);
                        binaryWriter.Write(packet);
                        crc32.SlurpBlock(memoryStream.GetBuffer(), 0, 8 + packet.Length);
                        binaryWriter.Write(crc32.Crc32Result);

                        logger.debug("sending to socket: {0}", BitConverter.ToString(memoryStream.GetBuffer(), 0, (int) memoryStream.Position).Replace("-","").ToLower());
                        await socketToSend.Send(memoryStream.GetBuffer(), 0, (int) memoryStream.Position);
                    }
                }
            } catch (Exception e) {
                throw new MTProtoTransportException("unable to send packet", e);
            }
        }
        public bool TransportSend(byte[] packet) {
            //logger.debug("network send packet");
            lock (this) {
                if (state != NetworkGatewayState.ESTABLISHED) {
                    logger.warning("send error, state not established");
                    return false;
                }

                using (MemoryStream memoryStream = new MemoryStream()) {
                    using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) {
                        //Crc32 crc32 = new Crc32();
                        CRC32 crc32 = new CRC32();
                        binaryWriter.Write(packet.Length + 12);
                        binaryWriter.Write(sendCounter);
                        binaryWriter.Write(packet);
                        crc32.SlurpBlock(memoryStream.GetBuffer(), 0, 8+packet.Length);
                        binaryWriter.Write(crc32.Crc32Result);

                        byte[] transportPacket = memoryStream.ToArray();

                        //logger.info("send transport packet: {0}", BitConverter.ToString(transportPacket).Replace("-",""));

                        var args = new SocketAsyncEventArgs();
                        args.SetBuffer(transportPacket, 0, transportPacket.Length);

                        try {
                            socket.SendAsync(args);
                        }
                        catch (Exception e) {
                            logger.warning("transport packet send error: {0}", e);
                            /*
                        if(state != NetworkGatewayState.DISPOSED) {
                            state = NetworkGatewayState.INIT;
                            Connect(host, port);
                        }*/
                            TryReconnect();
                            return false;
                        }

                        sendCounter++;
                        return true;
                    }
                }
            }
        }