func NewTorrent(torrent string) (metaInfo *bencode.MetaInfo, err os.Error) { var input io.ReadCloser if strings.HasPrefix(torrent, "http:") { // 6g compiler bug prevents us from writing r, _, err := var r *http.Response if r, _, err = http.Get(torrent); err != nil { return } input = r.Body } else { if input, err = os.Open(torrent, os.O_RDONLY, 0666); err != nil { return } } // We need to calcuate the sha1 of the Info map, including every value in the // map. The easiest way to do this is to read the data using the Decode // API, and then pick through it manually. var m interface{} m, err = bencode.Decode(input) input.Close() if err != nil { err = os.NewError("Couldn't parse torrent file phase 1: " + err.String()) return } topMap, ok := m.(map[string]interface{}) if !ok { err = os.NewError("Couldn't parse torrent file phase 2.") return } infoMap, ok := topMap["info"] if !ok { err = os.NewError("Couldn't parse torrent file. info") return } var b bytes.Buffer if err = bencode.Marshal(&b, infoMap); err != nil { return } hash := sha1.New() hash.Write(b.Bytes()) var m2 bencode.MetaInfo err = bencode.Unmarshal(&b, &m2.Info) if err != nil { return } //log.Println(m2.Info) m2.Infohash = string(hash.Sum()) m2.Announce = getString(topMap, "announce") m2.CreationDate = getString(topMap, "creation date") m2.Comment = getString(topMap, "comment") m2.CreatedBy = getString(topMap, "created by") m2.Encoding = getString(topMap, "encoding") m2.Announce_list = append(getArrayString(topMap, "announce-list"), m2.Announce) metaInfo = &m2 return }
func (t *Tracker) Request(num_peers int) (err os.Error) { // Prepare request to make to the tracker left := (t.bitfield.Len() - t.bitfield.Count()) * t.pieceLength if len(t.status) == 0 && !t.completed { if left == 0 { t.status = "completed" } } url := fmt.Sprint(t.url, "?", "info_hash=", http.URLEscape(t.infohash), "&peer_id=", http.URLEscape(t.peerId), "&port=", http.URLEscape(t.port), "&uploaded=", http.URLEscape(strconv.Itoa64(t.uploaded)), "&downloaded=", http.URLEscape(strconv.Itoa64(t.downloaded)), "&left=", http.URLEscape(strconv.Itoa64(left)), "&numwant=", http.URLEscape(strconv.Itoa(num_peers)), "&status=", http.URLEscape(t.status), "&compact=1") if len(t.trackerId) > 0 { url += "&tracker_id=" + http.URLEscape(t.trackerId) } /* r, _, err := http.Get(url) if err != nil { return } defer r.Body.Close() if r.StatusCode >= 400 { data, _ := ioutil.ReadAll(r.Body) reason := "Bad Request " + string(data) log.Println(reason) err = os.NewError(reason) return } var tr2 TrackerResponse err = bencode.Unmarshal(r.Body, &tr2) r.Body.Close() if err != nil { return } tr = &tr2 return */ response, _, err := http.Get(url) if err != nil { return } defer response.Body.Close() // Check if request was succesful if response.StatusCode != http.StatusOK { data, _ := ioutil.ReadAll(response.Body) reason := "Bad Request " + string(data) err = os.NewError(reason) return } // Create new TrackerResponse and decode the data var tr bencode.TrackerResponse err = bencode.Unmarshal(response.Body, &tr) if err != nil { return } t.interval = tr.Interval t.min_interval = tr.Min_interval if len(tr.Tracker_id) > 0 { t.trackerId = tr.Tracker_id } // Obtain new peers list peers := list.New() //log.Println("Tracker -> Decoded", len(tr.Peers), "peers") for i := 0; i < len(tr.Peers); i = i + 6 { peers.PushFront(fmt.Sprintf("%d.%d.%d.%d:%d", tr.Peers[i+0], tr.Peers[i+1], tr.Peers[i+2], tr.Peers[i+3], binary.BigEndian.Uint16([]byte(tr.Peers[i+4:i+6])))) //ip := fmt.Sprintf("%d.%d.%d.%d", peers[i+0], peers[i+1], peers[i+2], peers[i+3]) //port := int64(binary.BigEndian.Uint16(peers[i+4:i+6])) //tracker.Peers = appendPeer(tracker.Peers, Peer{Ip: ip, Port: port}) } /*for _, peer := range tr.Peers { peers.PushFront(fmt.Sprintf("%s:%d", peer.Ip, peer.Port)) }*/ //log.Println("Tracker -> Received", msgPeers.Len(), "peers") // Send the new data to the PeerMgr process t.trackerMgr.SavePeers(peers) if t.status == "completed" { t.completed = true } t.status = "" return }