public void SendMetadataCore(string expectedPath) { var connection = pair.Incoming; // 1) Send local handshake. We've already received the remote handshake as part // of the Connect method. SendMessage( new HandshakeMessage(rig.Manager.InfoHash, new string('g', 20), VersionInfo.ProtocolStringV100, true, true), connection); var exHand = new ExtendedHandshakeMessage(rig.Torrent.Metadata.Length); exHand.Supports.Add(LTMetadata.Support); SendMessage(exHand, connection); // 2) Receive the metadata requests from the other peer and fulfill them var buffer = rig.Torrent.Metadata; var length = (buffer.Length + 16383)/16384; PeerMessage m; while (length > 0 && (m = ReceiveMessage(connection)) != null) { var metadata = m as LTMetadata; if (metadata != null) { if (metadata.MetadataMessageType == LTMetadata.eMessageType.Request) { metadata = new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Data, metadata.Piece, buffer); SendMessage(metadata, connection); length--; } } } // We've sent all the pieces. Now we just wait for the torrentmanager to process them all. while (rig.Manager.Mode is MetadataMode) Thread.Sleep(10); Assert.True(File.Exists(expectedPath)); var torrent = Torrent.Load(expectedPath); Assert.Equal(rig.Manager.InfoHash, torrent.InfoHash); }
protected virtual void HandleLtMetadataMessage(PeerId id, LTMetadata message) { if (message.MetadataMessageType == LTMetadata.eMessageType.Request) { if (id.TorrentManager.HasMetadata) id.Enqueue(new LTMetadata(id, LTMetadata.eMessageType.Data, message.Piece, id.TorrentManager.Torrent.Metadata)); else id.Enqueue(new LTMetadata(id, LTMetadata.eMessageType.Reject, message.Piece)); } }
private void RequestNextNeededPiece(PeerId id) { int index = bitField.FirstFalse(); if (index == -1) return;//throw exception or switch to regular? LTMetadata m = new LTMetadata(id, LTMetadata.eMessageType.Request, index); id.Enqueue(m); requestTimeout = DateTime.Now.Add(timeout); }
protected override void HandleLtMetadataMessage(PeerId id, LTMetadata message) { base.HandleLtMetadataMessage(id, message); switch (message.MetadataMessageType) { case LTMetadata.eMessageType.Data: if (stream == null) throw new Exception("Need extention handshake before ut_metadata message."); stream.Seek(message.Piece * LTMetadata.BlockSize, SeekOrigin.Begin); stream.Write(message.MetadataPiece, 0, message.MetadataPiece.Length); bitField[message.Piece] = true; if (bitField.AllTrue) { byte[] hash; stream.Position = 0; using (SHA1 hasher = HashAlgoFactory.Create<SHA1>()) hash = hasher.ComputeHash(stream); if (!Manager.InfoHash.Equals (hash)) { bitField.SetAll(false); } else { Torrent t; stream.Position = 0; BEncodedDictionary dict = new BEncodedDictionary(); dict.Add ("info", BEncodedValue.Decode(stream)); // FIXME: Add the trackers too if (Torrent.TryLoad(dict.Encode (), out t)) { try { if (Directory.Exists(savePath)) savePath = Path.Combine (savePath, Manager.InfoHash.ToHex() + ".torrent"); File.WriteAllBytes(savePath, dict.Encode ()); } catch (Exception ex) { Logger.Log(null, "*METADATA EXCEPTION* - Can not write in {0} : {1}", savePath, ex); Manager.Error = new Error (Reason.WriteFailure, ex); Manager.Mode = new ErrorMode(Manager); return; } t.TorrentPath = savePath; Manager.Torrent = t; SwitchToRegular(); } else { bitField.SetAll(false); } } } //Double test because we can change the bitfield in the other block if (!bitField.AllTrue) { RequestNextNeededPiece(id); } break; case LTMetadata.eMessageType.Reject: //TODO //Think to what we do in this situation //for moment nothing ;) //reject or flood? break; case LTMetadata.eMessageType.Request://ever done in base class but needed to avoid default break; default: throw new MessageException(string.Format("Invalid messagetype in LTMetadata: {0}", message.MetadataMessageType)); } }