Beispiel #1
0
func (tracker *Tracker) sendHTTPRequest(data *TrackerRequestData) error {
	var eventString string
	switch data.event {
	case TrackerEventCompleted:
		eventString = "event=completed&"
	case TrackerEventStarted:
		eventString = "event=started&"
	case TrackerEventStopped:
		eventString = "event=stopped&"
	}

	httpResponse, err := http.Get(
		fmt.Sprintf("%s?%speer_id=%s&info_hash=%s&left=%d&compact=1&downloaded=%d&uploaded=%d&port=6881",
			tracker.announceURL,
			eventString,
			url.QueryEscape(string(tracker.torrent.peerID)),
			url.QueryEscape(string(tracker.torrent.getInfoHash())),
			data.remaining,
			data.downloaded,
			data.uploaded,
		),
	)
	if err != nil {
		return err
	}
	defer httpResponse.Body.Close()

	if httpResponse.StatusCode != http.StatusOK {
		return fmt.Errorf("bad response from tracker (%d): %s",
			httpResponse.StatusCode, httpResponse.Status)
	}

	resp, err := bencode.Decode(httpResponse.Body)
	if err != nil {
		return err
	}

	if failureReason, exists := resp["failure reason"]; exists {
		return errors.New(failureReason.(string))
	}

	tracker.interval = resp["interval"].(int64)
	tracker.torrent.peersChannel <- resp["peers"]
	return nil
}
Beispiel #2
0
func (torrent *Torrent) Open(filename string) error {
	torrent.exitFlag = false
	torrent.setPeerId()

	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	data, err := bencode.Decode(file)
	if err != nil {
		return err
	}

	if announceLists, ok := data["announce-list"].([]interface{}); ok {
		for _, announceList := range announceLists {
			for _, announceURL := range announceList.([]interface{}) {
				torrent.parseTrackerURL(announceURL.(string))
			}
		}
	} else {
		torrent.parseTrackerURL(data["announce"].(string))
	}

	if comment, ok := data["comment"]; ok {
		torrent.Comment = comment.(string)
	}

	info := data["info"].(map[string]interface{})
	torrent.Name = info["name"].(string)
	torrent.PieceLength = info["piece length"].(int64)

	infoHash := sha1.Sum(bencode.Encode(info))

	// Set handshake
	var buffer bytes.Buffer
	buffer.WriteByte(19) // length of the string "BitTorrent Protocol"
	buffer.WriteString("BitTorrent protocol")
	buffer.WriteString("\x00\x00\x00\x00\x00\x00\x00\x00") // reserved
	buffer.Write(infoHash[:])
	buffer.Write(torrent.peerID)
	torrent.handshake = buffer.Bytes()

	// Set pieces
	pieces := info["pieces"].(string)
	for i := 0; i < len(pieces); i += 20 {
		torrent.Pieces = append(torrent.Pieces, TorrentPiece{
			hash: pieces[i : i+20],
		})
	}

	if err := os.Mkdir("Downloads", 0700); err != nil && !os.IsExist(err) {
		return err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	base := filepath.Join(cwd, "Downloads")

	// Set files
	if files, exists := info["files"]; exists {
		dirName := filepath.Join("Downloads", info["name"].(string))
		if err := torrent.validatePath(base, dirName); err != nil {
			return err
		}

		base := filepath.Join(cwd, dirName)

		for _, v := range files.([]interface{}) {
			v := v.(map[string]interface{})
			torrent.TotalSize += v["length"].(int64)
		}

		// Multiple files
		var begin int64
		for k, v := range files.([]interface{}) {
			v := v.(map[string]interface{})

			// Set up directory structure
			pathList := v["path"].([]interface{})
			pathElements := []string{dirName}
			for i := 0; i < len(pathList)-1; i++ {
				pathElements = append(pathElements, pathList[i].(string))
			}

			path := filepath.Join(pathElements...)
			fullPath := filepath.Join(path, pathList[len(pathList)-1].(string))
			if err := torrent.validatePath(base, fullPath); err != nil {
				return err
			}

			if len(path) != 0 {
				if err := os.MkdirAll(path, 0700); err != nil {
					return err
				}
			}

			length := v["length"].(int64)

			file, err := os.OpenFile(fullPath, os.O_RDWR, 0600)
			if err == nil {
				torrent.findCompletedPieces(file, begin, length, k)
				file.Close()
			}

			torrent.files = append(torrent.files, File{fullPath, begin, length})
			begin += length
		}
	} else {
		// Single file
		fileName := filepath.Join("Downloads", info["name"].(string))
		if err := torrent.validatePath(base, fileName); err != nil {
			return err
		}

		length := info["length"].(int64)
		torrent.TotalSize = length

		file, err := os.OpenFile(fileName, os.O_RDWR, 0600)
		if err == nil {
			torrent.findCompletedPieces(file, 0, length, 0)
			file.Close()
		}
		torrent.files = []File{{fileName, 0, length}}
	}

	fileWriterChannel = make(chan *FileWriterMessage)
	go fileWriterListener()

	return nil
}