protected TLFileBase GetFile(TLInt dcId, TLInputFileLocationBase location, TLInt offset, TLInt limit, out TLRPCError er, out bool isCanceled)
        {
            var        manualResetEvent = new ManualResetEvent(false);
            TLFileBase result           = null;
            TLRPCError outError         = null;
            var        outIsCanceled    = false;

            _mtProtoService.GetFileAsync(dcId, location, offset, limit,
                                         file =>
            {
                result = file;
                manualResetEvent.Set();
            },
                                         error =>
            {
                outError = error;

                if (error.CodeEquals(ErrorCode.INTERNAL) ||
                    (error.CodeEquals(ErrorCode.BAD_REQUEST) && (error.TypeEquals(ErrorType.LOCATION_INVALID) || error.TypeEquals(ErrorType.VOLUME_LOC_NOT_FOUND))) ||
                    (error.CodeEquals(ErrorCode.NOT_FOUND) && error.Message != null && error.Message.ToString().StartsWith("Incorrect dhGen")))
                {
                    outIsCanceled = true;

                    manualResetEvent.Set();
                    return;
                }

                int delay;
                lock (_randomRoot)
                {
                    delay = _random.Next(1000, 3000);
                }

                Execute.BeginOnThreadPool(TimeSpan.FromMilliseconds(delay), () => manualResetEvent.Set());
            });

            manualResetEvent.WaitOne();
            er         = outError;
            isCanceled = outIsCanceled;

            return(result);
        }
        protected TLFileBase GetCdnFile(TLFileCdnRedirect redirect, TLInt offset, TLInt limit, out TLCdnFileReuploadNeeded reuploadNeeded, out TLRPCError er, out bool isCanceled, out bool isTokenInvalid)
        {
            var        manualResetEvent = new ManualResetEvent(false);
            TLFileBase result           = null;
            TLCdnFileReuploadNeeded outReuploadNeeded = null;
            TLRPCError outError          = null;
            var        outIsCanceled     = false;
            var        outIsTokenInvalid = false;

            _mtProtoService.GetCdnFileAsync(redirect.DCId, redirect.FileToken, offset, limit,
                                            cdnFileBase =>
            {
                var cdnFile = cdnFileBase as TLCdnFile;
                if (cdnFile != null)
                {
                    var iv      = GetIV(redirect.EncryptionIV.Data, offset);
                    var counter = offset.Value / 16;
                    iv[15]      = (byte)(counter & 0xFF);
                    iv[14]      = (byte)((counter >> 8) & 0xFF);
                    iv[13]      = (byte)((counter >> 16) & 0xFF);
                    iv[12]      = (byte)((counter >> 24) & 0xFF);

                    var key = redirect.EncryptionKey.Data;

                    var ecount_buf = new byte[0];
                    var num        = 0u;
                    var bytes      = Utils.AES_ctr128_encrypt(cdnFile.Bytes.Data, key, ref iv, ref ecount_buf, ref num);

                    result = new TLFile {
                        Bytes = TLString.FromBigEndianData(bytes)
                    };
                }

                var cdnFileReuploadNeeded = cdnFileBase as TLCdnFileReuploadNeeded;
                if (cdnFileReuploadNeeded != null)
                {
                    outReuploadNeeded = cdnFileReuploadNeeded;
                }

                manualResetEvent.Set();
            },
                                            error =>
            {
                outError = error;

                if (error.CodeEquals(ErrorCode.INTERNAL) ||
                    (error.CodeEquals(ErrorCode.BAD_REQUEST) && (error.TypeEquals(ErrorType.LOCATION_INVALID) || error.TypeEquals(ErrorType.VOLUME_LOC_NOT_FOUND))) ||
                    (error.CodeEquals(ErrorCode.NOT_FOUND) && error.Message != null && error.Message.ToString().StartsWith("Incorrect dhGen")))
                {
                    outIsCanceled = true;

                    manualResetEvent.Set();
                    return;
                }
                if (error.CodeEquals(ErrorCode.BAD_REQUEST) && error.TypeEquals(ErrorType.FILE_TOKEN_INVALID))
                {
                    outIsTokenInvalid = true;

                    manualResetEvent.Set();
                    return;
                }

                int delay;
                lock (_randomRoot)
                {
                    delay = _random.Next(1000, 3000);
                }

                Execute.BeginOnThreadPool(TimeSpan.FromMilliseconds(delay), () => manualResetEvent.Set());
            });

            manualResetEvent.WaitOne();
            reuploadNeeded = outReuploadNeeded;
            er             = outError;
            isCanceled     = outIsCanceled;
            isTokenInvalid = outIsTokenInvalid;

            return(result);
        }