func NewTrackerResponse(responseStr string) (*TrackerResponse, error) { lex := bencoding.BeginLexing("response", responseStr, bencoding.LexBegin) tokens := bencoding.Collect(lex) parser := bencoding.Parse(tokens) o := parser.Output.(map[string]interface{}) // TODO: Handle required/optional fields response := &TrackerResponse{} addStringField("failure reason", &response.FailureReason, o["failure reason"], false) if response.FailureReason != "" { return response, errors.New("Tracker Request Failure") } err := addIntField("complete", &response.Complete, o["complete"], true) if err != nil { return response, err } err = addIntField("incomplete", &response.Incomplete, o["incomplete"], true) if err != nil { return response, err } addIntField("downloaded", &response.Downloaded, o["downloaded"], false) err = addIntField("interval", &response.Interval, o["interval"], true) if err != nil { return response, err } addIntField("min_interval", &response.MinInterval, o["min interval"], false) // TODO: Handle dictionary vs binary peer models peers := make([]Peer, 0) if _, ok := o["peers"]; !ok { return response, errors.New(fmt.Sprint("Missing Required Field: peers")) } peerBytes := o["peers"].([]byte) for i := 0; i < len(peerBytes); i += 6 { ip := net.IPv4(peerBytes[i+3], peerBytes[i+2], peerBytes[i+1], peerBytes[i]) port := binary.BigEndian.Uint16(peerBytes[i+4 : i+6]) peers = append(peers, Peer{IP: ip, Port: port}) } response.Peers = peers return response, nil }
func NewMetainfo(filename string) *Metainfo { data, err := ioutil.ReadFile(filename) if err != nil { panic(err) } torrentStr := string(data) lex := bencoding.BeginLexing(".torrent", torrentStr, bencoding.LexBegin) tokens := bencoding.Collect(lex) rawInfoVal := bencoding.GetBencodedInfo(tokens) output := bencoding.Parse(tokens) result := output.Output.(map[string]interface{}) metainfo := &Metainfo{} // Required fields if result["info"] != nil { addInfoFields(metainfo, result["info"].(map[string]interface{})) metainfo.Info.Hash = getRightEncodedSHA1(rawInfoVal) } else { panic("MISSING REQUIRED FIELD: info") } addStringField("announce", &metainfo.Announce, result["announce"], true) // Optional fields if result["announce-list"] != nil { // TODO: parse announce-list } if result["creation date"] != nil { creationDate := int64(result["creation date"].(int)) t := time.Unix(creationDate, 0) metainfo.CreationDate = t } addStringField("comment", &metainfo.Comment, result["comment"], false) addStringField("created by", &metainfo.CreatedBy, result["created by"], false) addStringField("encoding", &metainfo.Encoding, result["encoding"], false) return metainfo }
func main() { // Set up logging to file and stdout f, err := os.OpenFile("torro.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) if err != nil { fmt.Printf("Error opening file: %v", err) } defer f.Close() mw := io.MultiWriter(os.Stdout, f) log.SetOutput(mw) println("TORRO!\n\n\n") // Read command line flags and arguments pPrint := flag.String("print", "metainfo", "either tokens, parsed, or metainfo") pUPNP := flag.Bool("upnp", false, "open port through UPNP") pAnnounce := flag.Bool("announce", false, "send announce request to tracker") flag.Parse() var filename string fmt.Println(flag.Args()) if len(flag.Args()) > 0 { filename = flag.Args()[0] } else { filename = "testfiles/TheInternetsOwnBoyTheStoryOfAaronSwartz_archive.torrent" } if *pUPNP { fmt.Println("Opening port through UPNP") d, _ := upnp.Discover() ip, _ := d.ExternalIP() _ = d.Forward(55555, "torro") defer d.Clear(55555) log.Printf("Discovered: %q\n", d) log.Printf("External IP: %q\n", ip) log.Printf("Location: %q\n", d.Location()) } // Read actual .torrent file fmt.Println("Parsing: ", filename) data, err := ioutil.ReadFile(filename) if err != nil { panic(err) } // Lex and Parse .torrent file torrentStr := string(data) lex := bencoding.BeginLexing(".torrent", torrentStr, bencoding.LexBegin) tokens := bencoding.Collect(lex) output := bencoding.Parse(tokens) result := output.Output.(map[string]interface{}) // Read .torrent metainfo and make request to the announce URL metainfo := structure.NewMetainfo(filename) c := client.NewTrackerClient() req := structure.NewTrackerRequest(metainfo) req.PeerID = "-qB3230-u~QGMmUs~yXH" req.Port = 55555 req.Compact = true req.NoPeerID = true if *pAnnounce { res, err := c.MakeAnnounceRequest(req, client.TrackerRequestStarted) if err != nil { fmt.Println(res.FailureReason) panic(err.Error()) } fmt.Println(res) log.Println("StartListening") port := 55555 peerId := []byte("-TR2840-nj5ovtkoz2ed") s := client.NewBTService(port, peerId) s.StartListening() } switch *pPrint { case "tokens": PrintTokens(&tokens) case "parsed": PrintParsedStructure(result) case "metainfo": PrintMetainfo(metainfo) default: PrintMetainfo(metainfo) } // time.Sleep(time.Second * 60) }