void PieceDownloader()
        {
            var sha1 = SHA1.Create();
            int piece;

            while ((piece = GetFreePiece()) != -1)
            {
                try
                {
                    Interlocked.Increment(ref urlShift);

                    for (var i = 0; i < urls.Count; i++)
                    {
                        if (IsAborted)
                        {
                            return;
                        }
                        var url = urls[(urlShift + i) % urls.Count];

                        lock (invalidUrl) if (invalidUrl.Contains(url))
                            {
                                continue;
                            }

                        var    pg = new PieceGet(url, torrent.PieceLength * piece, GetPieceLength(piece));
                        byte[] buf;
                        bool   invalid;
                        var    ok = pg.Download(ref done, out buf, out invalid);
                        if (invalid)
                        {
                            lock (invalidUrl) if (!invalidUrl.Contains(url))
                                {
                                    invalidUrl.Add(url);
                                }
                        }
                        if (IsAborted)
                        {
                            return;
                        }
                        if (ok && torrent.Pieces.IsValid(sha1.ComputeHash(buf), piece))
                        {
                            var len = GetPieceLength(piece);
                            var pos = torrent.PieceLength * piece;
                            //Utils.StartAsync(() =>
                            //{
                            lock (file)
                            {
                                file.Seek(pos, SeekOrigin.Begin);
                                file.Write(buf, 0, len);
                            }
                            //});
                            pieceStates[piece] = PieceState.Done;
                            break;
                        }
                        else
                        {
                            Trace.TraceWarning("Piece {0} failed for {1}", piece, url);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Error while getting piece {0}:{1}", piece, ex);
                }
                if (pieceStates[piece] != PieceState.Done)
                {
                    pieceStates[piece] = PieceState.Failed;
                }
            }

            lock (block) Monitor.Pulse(block);
        }
    void PieceDownloader()
    {
      var sha1 = SHA1.Create();
      int piece;
      while ((piece = GetFreePiece()) != -1)
      {
        try
        {
          Interlocked.Increment(ref urlShift);

          for (var i = 0; i < urls.Count; i++)
          {
            if (IsAborted) return;
            var url = urls[(urlShift + i)%urls.Count];
            
            lock (invalidUrl) if (invalidUrl.Contains(url)) continue;

            var pg = new PieceGet(url, torrent.PieceLength*piece, GetPieceLength(piece));
            byte[] buf;
            bool invalid;
            var ok = pg.Download(ref done, out buf, out invalid);
            if (invalid)
            {
              lock (invalidUrl) if (!invalidUrl.Contains(url)) invalidUrl.Add(url);
            }
            if (IsAborted) return;
            if (ok && torrent.Pieces.IsValid(sha1.ComputeHash(buf), piece))
            {
              var len = GetPieceLength(piece);
              var pos = torrent.PieceLength*piece;
              //Utils.StartAsync(() =>
              //{
              lock (file)
              {
                file.Seek(pos, SeekOrigin.Begin);
                file.Write(buf, 0, len);
              }
              //});
              pieceStates[piece] = PieceState.Done;
              break;
            }
            else Trace.TraceWarning("Piece {0} failed for {1}", piece, url);
          }
        }
        catch (Exception ex)
        {
          Trace.TraceError("Error while getting piece {0}:{1}", piece, ex);
        }
        if (pieceStates[piece] != PieceState.Done) pieceStates[piece] = PieceState.Failed;
      }

      lock (block) Monitor.Pulse(block);
    }