func main() { loggerconfig.Use() if len(os.Args) != 2 { logger.Fatalf("Usage: %v PATH", os.Args[0]) return } weakrand.Seed(time.Now().UTC().UnixNano()) path := os.Args[1] infoDict, err := bittorrent.GenerateTorrentMetaInfo(bittorrent.CreationOptions{ Path: path, PieceLength: PieceLength, ForceMultiFile: false, }) if err != nil { logger.Fatalf("Error generating torrent: %v", err) return } infoData, err := bencoding.Encode(infoDict) if err != nil { logger.Fatalf("Error encoding torrent infodict (for hashing): %v", err) return } torrentDict := bencoding.Dict{ "info": infoDict, "nodes": bencoding.List{ bencoding.List{ bencoding.String("127.0.0.1"), bencoding.Int(6881), }, }, } torrentData, err := bencoding.Encode(torrentDict) if err != nil { logger.Fatalf("Error encoding torrent data: %v", err) return } hasher := sha1.New() hasher.Write(infoData) hash := hasher.Sum(nil) infoHash := bittorrent.BTID(hash) logger.Info("Generated torrent btih=%v.", infoHash) os.Stdout.Write(torrentData) os.Stdout.Sync() }
func (p *swarmPeer) writeHandshake(peerId BTID, infohash BTID) { // BitTorrent Handshake header := []byte(peerProtocolHeader) extensionFlags := make([]byte, 8) extensionFlags[5] |= 0x10 // indicate extension protocol support p.conn.Write(header) p.conn.Write(extensionFlags) p.conn.Write([]byte(infohash)) p.conn.Write([]byte(peerId)) // If we had any pieces, we would need to indicate so here, but we don't. // writeMessage(w, msgBitfield, piecesBitfield) // TODO: move this somewhere else and only fire it after we check their extension flags // Write Extension Protcol Handshake handshakeBody, err := bencoding.Encode(bencoding.Dict{ "v": bencoding.String("jbitor 0.0.0"), "m": bencoding.Dict{ "ut_metadata": bencoding.Int(ourUtMetadataId), "ut_pex": bencoding.Int(ourUtPexId), }, "p": bencoding.Int(PORT), }) if err != nil { logger.Info("unable to encode extension handshake: %v", err) return } logger.Info("sent extension handshake") p.writeMessage(msgExtended, append([]byte{extensionHandshakeId}, handshakeBody...)) }
func (c *localNodeClient) Save() (err error) { var ( nodeData []byte ) if c.localNode == nil { err = errors.New("Client is closed.") return } nodeData, err = bencoding.Encode(c.localNode) if err != nil { return } err = c.openDataFile.Truncate(0) if err != nil { return } _, err = c.openDataFile.WriteAt(nodeData, 0) if err != nil { return } err = c.openDataFile.Sync() if err != nil { return } logger.Info("Saved DHT client state.") return }
func cmdJsonToBencoding(args []string) { if len(args) != 0 { logger.Fatalf("Usage: %v to-bencoding < FOO.bittorrent.json > FOO.torrent", os.Args[0]) return } data, err := ioutil.ReadAll(os.Stdin) if err != nil { logger.Fatalf("Error reading stdin: %v", err) return } var decoded *interface{} err = json.Unmarshal(data, &decoded) if err != nil { logger.Fatalf("Error decoding JSON from stdin: %v", err) return } bval, err := bencoding.FromJsonable(*decoded) if err != nil { logger.Fatalf("Error converting jsonable to bencodable: %v", err) return } encoded, err := bencoding.Encode(bval) if err != nil { logger.Fatalf("Error bencoding value: %v", err) return } os.Stdout.Write(encoded) os.Stdout.Sync() }
func (local *localNode) sendQuery(remote *RemoteNode, queryType string, arguments bencoding.Dict) (query *RpcQuery) { // XXX(JB): These should probably have a distinct warning logger. if remote.Flooded() { logger.Info("WARNING: flooding node %v.", remote) } if remote.Status() == STATUS_BAD { logger.Info("WARNING: querying bad node %v.", remote) } query = new(RpcQuery) query.Result = make(chan *bencoding.Dict) query.Err = make(chan error) query.Remote = remote if arguments == nil { arguments = bencoding.Dict{} } arguments["id"] = bencoding.String(local.Id) // XXX: assert that these keys are not already present? message := bencoding.Dict{ "y": bencoding.String("q"), "q": bencoding.String(queryType), "a": arguments, } transactionId := new([4]byte) if _, err := rand.Read(transactionId[:]); err != nil { query.Err <- err close(query.Result) close(query.Err) return } query.TransactionId = string(transactionId[:]) local.OutstandingQueries[query.TransactionId] = query message["t"] = bencoding.String(query.TransactionId) encodedMessage, err := bencoding.Encode(message) if err != nil { query.Err <- err close(query.Result) close(query.Err) return } remote.LastRequestTo = time.Now() go func() { // XXX: Does this wait longer than necessary to send the packet? local.Connection.WriteTo(encodedMessage, &remote.Address) }() return query }
// Requests the next piece of metadata we don't yet have from this peer. // Must only be called if we know the peer supports it. // Does nothing if we already have all of the pieces they claim. func (p *swarmPeer) requestNextMetadataPiece() { if !p.infoComplete { i := len(p.infoPieces) requestBody, err := bencoding.Encode(bencoding.Dict{ "msg_type": bencoding.Int(0), // request piece "piece": bencoding.Int(i), }) if err != nil { logger.Error("unable to encode extension metadata request: %v", err) return } logger.Notice("requesting piece %v of metadata!", i) p.writeMessage(msgExtended, append([]byte{p.extensions.bep9MetadataExchange.id}, requestBody...)) } }
func main() { loggerconfig.Use() if len(os.Args) != 2 { logger.Fatalf("Usage: %v INFOHASH < INFOHASH.peers", os.Args[0]) return } weakrand.Seed(time.Now().UTC().UnixNano()) infoHash, err := bittorrent.BTIDFromHex(os.Args[1]) if err != nil { logger.Fatalf("Specified string was not a valid hex infohash [%v].", err) return } peers := make([]net.TCPAddr, 0) dec := json.NewDecoder(os.Stdin) dec.Decode(&peers) logger.Info("Loaded peers: %v", peers) client := bittorrent.OpenClient() swarm := client.Swarm(infoHash) for _, peer := range peers { swarm.AddPeer(peer) } logger.Info("getting info") info := swarm.Info() logger.Info("got info: %v", info) torrentFileData, err := bencoding.Encode(bencoding.Dict{ "info": info, "announce-list": bencoding.List{}, "nodes": bencoding.List{}, }) if err != nil { logger.Fatalf("error encoding torrent file: %v:", err) } os.Stdout.Write(torrentFileData) }
// /INFOHASH.torrent // func (wc *T) handleTorrentFileRequest(w http.ResponseWriter, r *http.Request, infoHash bittorrent.BTID) { logger.Notice("Serving %v.torrent file request", infoHash) info := wc.btClient.Swarm(infoHash, wc.dhtClient.GetPeers(infoHash).ReadNewPeers()).Info() data, err := bencoding.Encode(bencoding.Dict{ "info": info, "announce-list": bencoding.List{}, "nodes": bencoding.List{}, }) if err != nil { logger.Error("unable to encode torrent: %v", err) return } w.Header().Set("Content-Type", "application/x-bittorrent") // TODO: encode filename & filename* properly w.Header().Set("Content-Disposition", "attachment;filename="+string(info["name"].(bencoding.String))+".torrent") w.Write(data) }