Example #1
0
func writeEncoded(c appengine.Context, w http.ResponseWriter, data interface{}) {
	newEncoder := bencode.NewEncoder(w)
	if err := newEncoder.Encode(data); err != nil {
		c.Errorf("Failed to encode data: %s", err)
		writeInternalError(w)
	}
}
Example #2
0
// Bencodes an arbitrary dictionary as a tracker response.
func encodeResponseMap(responseMap map[string]interface{}) io.Reader {
	responseBuf := bytes.NewBuffer(make([]byte, 0))
	encoder := bencode.NewEncoder(responseBuf)
	_ = encoder.Encode(responseMap)

	return responseBuf
}
Example #3
0
func (p *peerState) SendExtensions(supportedExtensions map[int]string,
	metadataSize int64) {

	handshake := ExtensionHandshake{
		M:            make(map[string]int, len(supportedExtensions)),
		V:            "Taipei-Torrent dev",
		MetadataSize: metadataSize,
	}

	for i, ext := range supportedExtensions {
		handshake.M[ext] = i
	}

	var buf bytes.Buffer
	err := bencode.NewEncoder(&buf).Encode(handshake)
	if err != nil {
		log.Println("Error when marshalling extension message")
		return
	}

	msg := make([]byte, 2+buf.Len())
	msg[0] = EXTENSION
	msg[1] = EXTENSION_HANDSHAKE
	copy(msg[2:], buf.Bytes())

	p.sendMessage(msg)
}
Example #4
0
// 读取种子信息
func ReadTorrent(r io.Reader) (meta MetaInfo, err error) {
	// 读取文件信息
	s, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}

	err = bencode.DecodeBytes(s, &meta)
	if err != nil {
		return
	}

	hash := sha1.New()
	err = bencode.NewEncoder(hash).Encode(meta.Info)
	if err != nil {
		return
	}

	meta.InfoHash = fmt.Sprintf("%02X", string(hash.Sum(nil)))

	return
	/*var m interface{}
	m, err = bencode.Decode(r)
	if err != nil {
		return
	}

	topMap, ok := m.(map[string]interface{})
	if !ok {
		return
	}

	infoMap, ok := topMap["info"]
	if !ok {
		return
	}

	var b bytes.Buffer
	if err = bencode.Marshal(&b, infoMap); err != nil {
		return
	}

	hash := sha1.New()
	hash.Write(b.Bytes())

	err = bencode.Unmarshal(&b, &meta.Info)
	if err != nil {
		return
	}

	meta.InfoHash = fmt.Sprintf("%X", string(hash.Sum(nil)))
	meta.Announce = getString(topMap, "announce")
	meta.Comment = getString(topMap, "comment")
	meta.CreatedBy = getString(topMap, "created by")
	meta.CreationDate = getInt64(topMap, "creation date")
	meta.Encoding = getString(topMap, "encoding")

	return*/
}
Example #5
0
// MD5Params returns the MD5 hash of the provided map[string]string.
// This could easily be extended to support hashing any datatype supported
// by bencode.
func MD5Params(val map[string]string) (string, error) {
	md5Writer := md5.New()
	enc := bencode.NewEncoder(md5Writer)
	if err := enc.Encode(val); err != nil {
		return "", err
	}
	return fmt.Sprintf("%x", md5Writer.Sum(nil)), nil
}
Example #6
0
// Returns the size of the representation of this metainfo as a bencoded
// dictionary
func (m *MetaInfo) Size() (sz int) {
	var buf bytes.Buffer
	err := bencode.NewEncoder(&buf).Encode(m)
	if err != nil {
		log.Fatal("Couldn't bencode this metainfo: ", err)
	}

	return buf.Len()
}
Example #7
0
func (m *MetaInfo) saveToDisk(dir string) (err error) {
	ihhex := fmt.Sprintf("%x", m.InfoHash)
	f, err := os.Create(filepath.Join(dir, ihhex))
	if err != nil {
		log.Println("Error when opening file for creation: ", err)
		return
	}
	defer f.Close()

	return bencode.NewEncoder(f).Encode(m)
}
Example #8
0
// Returns a bencoded version of the torrent's info dict.
func (t *TorrentFile) BencodeInfoDict() ([]byte, error) {
	infoBuffer := bytes.NewBuffer(make([]byte, 0))
	encoder := bencode.NewEncoder(infoBuffer)

	err := encoder.Encode(t.Info)
	if err != nil {
		fmt.Printf("error encoding torrent file: %s", err.Error())
	}

	return infoBuffer.Bytes(), err
}
Example #9
0
func benc(w http.ResponseWriter, req *http.Request) {
	enc := bencode.NewEncoder(w)
	if err := enc.Encode(map[string]interface{}{
		"foo": "bar",
		"baz": 2,
		"buf": []string{"baz", "bloof"},
	}); err != nil {
		log.Println(err)
	}
	log.Printf("Handled request from %s :)", req.RemoteAddr)
}
Example #10
0
func (query *Query) constructArgs(args interface{}) error {
	buf := new(bytes.Buffer)
	bencodeE := bencode.NewEncoder(buf)
	if err := bencodeE.Encode(args); err != nil {
		return err
	}

	data, err := encodeIntoBigEndian(buf)
	query.ProcedureData = data

	return err
}
Example #11
0
func announceRecover(w http.ResponseWriter) {
	err := recover()
	if err == nil {
		return
	}
	w.WriteHeader(http.StatusInternalServerError)

	enc := bencode.NewEncoder(w)
	enc.Encode(M{"failure reason": err})

	//DEBUG: newline for debugging
	fmt.Fprintln(w, "")
}
Example #12
0
// Converts torrent to SUPRA-PRIVATE torrent
//
// Sets the private flag to 1 and embeds the supplied secret and hash
// for authentication purposes.
//
// This torrent file SHOULD NOT be shared between users or statistics collection
// and anti-abuse mechanisms will be skewed for that user.
func (t *TorrentFile) WriteFile(secret, hash []byte) ([]byte, error) {
	fmt.Printf("writing file...")

	t.Announce = fmt.Sprintf("http://tracker.fatalsyntax.com:4200/%s/%s/announce", hex.EncodeToString(secret), hex.EncodeToString(hash))
	t.Encoding = "UTF-8"
	infoBuffer := bytes.NewBuffer(make([]byte, 0))
	encoder := bencode.NewEncoder(infoBuffer)

	err := encoder.Encode(t)

	if err != nil {
		return nil, err
	}

	return infoBuffer.Bytes(), nil

}
Example #13
0
func (cs *ControlSession) DoMetadata(msg []byte, p *peerState) (err error) {
	var message IHMessage
	err = bencode.NewDecoder(bytes.NewReader(msg)).Decode(&message)
	if err != nil {
		cs.log("Couldn't decode metadata message: ", err)
		return
	}
	if message.Port == 0 {
		return
	}

	// take his IP addr, use the advertised port
	ip := p.conn.RemoteAddr().(*net.TCPAddr).IP.String()
	port := strconv.Itoa(int(message.Port))
	peer := ip + ":" + port

	if cs.isNewerThan(message.Info.Rev) {
		return
	}

	var tmpInfoBuf bytes.Buffer
	err = bencode.NewEncoder(&tmpInfoBuf).Encode(message.Info)
	if err != nil {
		cs.log("Couldn't encode ih message, returning now")
		return err
	}
	rawInfo := tmpInfoBuf.Bytes()

	pub := [ed.PublicKeySize]byte(cs.ID.Pub)
	var sig [ed.SignatureSize]byte
	copy(sig[0:ed.SignatureSize], message.Sig)
	ok := ed.Verify(&pub, rawInfo, &sig)
	if !ok {
		return errors.New("Bad Signature")
	}

	var test IHMessage
	err = bencode.NewDecoder(bytes.NewReader(msg)).Decode(&test)
	cs.session.SaveIHMessage(msg)
	cs.Torrents <- Announce{
		infohash: message.Info.InfoHash,
		peer:     peer,
	}

	return
}
Example #14
0
// Encode's the `info` dictionary into a SHA1 hash; used to uniquely identify a torrent.
func (t *TorrentFile) EncodeInfo() []byte {
	//torrentDict := torrentMetainfo.(map[string]interface{})
	infoBytes := make([]byte, 0) //TODO: intelligenty size buffer based on info
	infoBuffer := bytes.NewBuffer(infoBytes)

	encoder := bencode.NewEncoder(infoBuffer)

	err := encoder.Encode(t.Info)
	if err != nil {
		fmt.Printf("error encoding torrent file: %s", err.Error())
	}

	hash := sha1.New()
	io.Copy(hash, infoBuffer)

	return hash.Sum(nil)
}
Example #15
0
// Returns the representation of this metainfo's info dict as a
// bencoded dictionary
func (m *MetaInfo) RawInfo() (b []byte) {
	if m.rawInfo != nil {
		return m.rawInfo
	}
	if m.Info == nil {
		return []byte{}
	}

	var buf bytes.Buffer
	err := bencode.NewEncoder(&buf).Encode(m.Info)
	if err != nil {
		log.Fatal("Couldn't bencode this metainfo's dict: ", err)
	}

	m.rawInfo = buf.Bytes()

	return m.rawInfo
}
Example #16
0
func (p *peerState) sendExtensionMessage(typ string, data interface{}) {
	if _, ok := p.theirExtensions[typ]; !ok {
		// They don't understand this extension
		return
	}

	var payload bytes.Buffer
	err := bencode.NewEncoder(&payload).Encode(data)
	if err != nil {
		log.Printf("Couldn't marshal extension message: ", err)
	}

	msg := make([]byte, 2+payload.Len())
	msg[0] = EXTENSION
	msg[1] = byte(p.theirExtensions[typ])
	copy(msg[2:], payload.Bytes())

	p.sendMessage(msg)
}
Example #17
0
func (w *Watcher) torrentify() (ih string, err error) {
	w.lock.Lock()
	defer w.lock.Unlock()

	meta, err := createMeta(w.watchedDir)
	if err != nil {
		log.Println(err)
		return
	}

	var buf bytes.Buffer
	err = bencode.NewEncoder(&buf).Encode(meta)
	if err != nil {
		return
	}
	w.session.SaveTorrent(buf.Bytes(), meta.InfoHash, time.Now().Format(time.RFC3339))

	return meta.InfoHash, err
}
Example #18
0
func NewMetaInfoFromContent(content []byte) (m *MetaInfo, err error) {

	var m1 MetaInfo
	err1 := bencode.DecodeString(string(content), &m1)
	if err1 != nil {
		err = errors.New("Couldn't parse torrent file: " + err1.Error())
		return
	}

	hash := sha1.New()
	err1 = bencode.NewEncoder(hash).Encode(m1.Info)
	if err1 != nil {
		return
	}

	m1.InfoHash = string(hash.Sum(nil))

	return &m1, nil
}
Example #19
0
func (cs *ControlSession) SetCurrent(ih string) error {
	if cs.currentIH == ih {
		return nil
	}

	parts := strings.Split(cs.rev, "-")
	if len(parts) != 2 {
		cs.logf("Invalid rev: %s\n", cs.rev)
		parts = []string{"0", ""}
	}

	counter, err := strconv.Atoi(parts[0])
	if err != nil {
		counter = 0
	}
	newCounter := strconv.Itoa(counter + 1)

	cs.logf("Updating rev with ih %x", ih)
	newRev := newCounter + "-" + fmt.Sprintf("%x", sha1.Sum([]byte(ih+parts[1])))

	mess, err := NewIHMessage(int64(cs.Port), ih, newRev, cs.ID.Priv)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	err = bencode.NewEncoder(&buf).Encode(mess)
	if err != nil {
		return err
	}
	err = cs.session.SaveIHMessage(buf.Bytes())
	if err != nil {
		return err
	}

	cs.currentIH = ih
	cs.rev = newRev

	cs.broadcast(mess)
	return nil
}
Example #20
0
func NewIHMessage(port int64, ih, rev string, priv id.PrivKey) (mm IHMessage, err error) {

	info := NewInfo{
		InfoHash: ih,
		Rev:      rev,
	}

	var buf bytes.Buffer
	err = bencode.NewEncoder(&buf).Encode(info)
	if err != nil {
		log.Println("[CONTROL] Couldn't encode ih message, returning now")
		return mm, err
	}

	var privarg [ed.PrivateKeySize]byte
	copy(privarg[:], priv[:])
	sig := ed.Sign(&privarg, buf.Bytes())

	return IHMessage{
		Info: info,
		Port: port,
		Sig:  string(sig[:]),
	}, nil
}
Example #21
0
func announce(c *Context) {
	defer announceRecover(c.w)

	log.Print(c.r.RawURL)
	a, err := ParseAnnounce(c.r)
	if err != nil {
		log.Panic("ERROR: ", err)
	}
	//grab the user by ip
	co := c.DB.C("users")

	var user *User
	co.Find(M{"ips": a.IP.String()}).One(&user)
	if user == nil {
		log.Panic("Unauthorized IP: ", a.IP)
	}

	//update the user in the database
	user.LastIP = a.IP.String()
	user.LastSeen = bson.Now()
	user.Update(a.InfoHash, a.Event, a.Left)
	co.Update(M{"_id": user.ID}, user)

	var peers []StructPeer
	query := co.Find(M{"info.infohash": a.InfoHash, "_id": M{"$ne": user.ID}})
	query.Limit(min(50, max(0, a.Numwant))) //bound between 0 <= n <= 50
	selector := M{"lastip": 1, "port": 1}
	if !a.NoPeerId {
		selector["peerid"] = 1
	}
	query.Select(selector)
	query.All(&peers)

	if query.Iter().Err() != nil {
		panic(query.Iter().Err())
	}

	enc := bencode.NewEncoder(c.w)
	//build the response
	if a.Compact {
		response := CompactAnnounceResponse{
			Interval:   30,
			Complete:   0,
			Incomplete: 0,
			Peers:      make([]string, len(peers)),
		}
		for i := range peers {
			response.Peers[i] = peers[i].Compact()
		}
		enc.Encode(response)
	} else {
		response := AnnounceResponse{
			Interval:   30,
			Complete:   0,
			Incomplete: 0,
			Peers:      peers,
		}
		enc.Encode(response)
	}
	fmt.Fprintln(c.w, "")
}
Example #22
0
func (t *Torrent) Resolve() error {
	if t.IsMagnet() {
		t.hasResolved = true
		return nil
	}

	var torrentFile struct {
		Announce     string                 `bencode:"announce"`
		AnnounceList [][]string             `bencode:"announce-list"`
		Info         map[string]interface{} `bencode:"info"`
	}

	// We don't need trackers for public torrents since we'll find them on the
	// DHT or public trackers
	if (t.InfoHash != "" && t.Name != "" && t.Peers > 0 && t.Seeds > 0) && (t.IsPrivate == false || len(t.Trackers) > 0) {
		return nil
	}

	parts := strings.Split(t.URI, "|")
	uri := parts[0]
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return err
	}
	if len(parts) > 1 {
		for _, part := range parts[1:] {
			keyVal := strings.SplitN(part, "=", 2)
			req.Header.Add(keyVal[0], keyVal[1])
		}
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		return err
	}
	dec := bencode.NewDecoder(resp.Body)

	// FIXME!!!!
	if err := dec.Decode(&torrentFile); err != nil {
		return err
	}
	if t.InfoHash == "" {
		hasher := sha1.New()
		bencode.NewEncoder(hasher).Encode(torrentFile.Info)
		t.InfoHash = hex.EncodeToString(hasher.Sum(nil))
	}
	if t.Name == "" {
		t.Name = torrentFile.Info["name"].(string)
	}
	if len(t.Trackers) == 0 {
		t.Trackers = append(t.Trackers, torrentFile.Announce)
		for _, trackers := range torrentFile.AnnounceList {
			t.Trackers = append(t.Trackers, trackers...)
		}
	}

	t.hasResolved = true

	t.initialize()

	return nil
}
Example #23
0
// Processes received queries
func (node *Node) processQuery(query *Query, addr net.Addr) error {
	procedureName := query.ProcedureName
	if procedure := node.procedures[procedureName]; procedure != nil {
		// Procedure exists (it's being served)
		method := procedure.Method
		function := method.Func

		// Initialize value
		argValue, replyValue := reflect.New(procedure.ArgType.Elem()), reflect.New(procedure.ReplyType.Elem())

		// Set value of arg
		argsReader := bytes.NewReader(query.ProcedureData)
		argsDecoder := bencode.NewDecoder(argsReader)
		err := argsDecoder.Decode(argValue.Interface())
		if err != nil {
			fmt.Errorf("qrp:", "Error decoding procedure data into value: %s\n", err.Error())
			return err
		}

		// Invoke the function
		function.Call([]reflect.Value{procedure.Receiver, argValue, replyValue})

		// Create reply
		reply := Reply{MessageID: query.MessageID}
		argsBuf := new(bytes.Buffer)
		argsEncoder := bencode.NewEncoder(argsBuf)
		argsEncoder.Encode(replyValue.Interface())
		reply.ReturnData, err = encodeIntoBigEndian(argsBuf)

		if err != nil {
			fmt.Errorf("qrp:", "Error encoding reply return data: %s\n", err.Error())
			return err
		}

		// Create message
		message := Message{Reply: &reply}

		// Encode message
		messageBuf := new(bytes.Buffer)
		messageEncoder := bencode.NewEncoder(messageBuf)
		err = messageEncoder.Encode(message)
		if err != nil {
			fmt.Errorf("qrp:", "Error encoding reply message into BEncode: %s\n", err.Error())
			return err
		}

		message_bigEndian, err := encodeIntoBigEndian(messageBuf)
		if err != nil {
			fmt.Errorf("qrp:", "Error encoding reply message into BigEndian: %s\n", err.Error())
			return err
		}

		// Send to host
		node.sendingMutex.Lock()
		node.connection.WriteTo(message_bigEndian, addr)
		node.sendingMutex.Unlock()

		return nil
	} else {
		return &BadProcedureError{procedureName}
	}
	return nil
}
Example #24
0
func Share(cliId string, workDir string, cliTarget string, trackers []string, useLPD bool, manualPeers []string) {
	shareID, err := id.NewFromString(cliId)
	if err != nil {
		fmt.Printf("Couldn't generate shareId: %s\n", err)
		return
	}
	sessionName := hex.EncodeToString(shareID.Infohash) + ".sql"
	session, err := sharesession.New(filepath.Join(workDir, sessionName))
	if err != nil {
		log.Fatal("Couldn't open session file: ", err)
	}

	fmt.Printf("WriteReadStore:\t%s\n     ReadStore:\t%s\n         Store:\t%s\n",
		shareID.WRS(), shareID.RS(), shareID.S())

	target := session.GetTarget()
	if target == "" {
		if cliTarget == "" {
			fmt.Println("Need a folder to share!")
			return
		}
		target = cliTarget
		session.SaveSession(target, shareID)
	} else if cliTarget != "" {
		fmt.Printf("Can't override folder already set to %s\n", target)
	}
	_, err = os.Stat(target)
	if err != nil {
		if os.IsNotExist(err) {
			os.MkdirAll(target, 0744)
		} else {
			fmt.Printf("%s is an invalid dir: %s\n", target, err)
			os.Exit(1)
		}
	}

	// Watcher
	watcher := &Watcher{
		PingNewTorrent: make(chan string),
	}
	if shareID.CanWrite() {
		watcher, err = NewWatcher(session, filepath.Clean(target))
		if err != nil {
			log.Fatal("Couldn't start watcher: ", err)
		}
	} else {
		watcher.PingNewTorrent = make(chan string, 1)
		watcher.PingNewTorrent <- session.GetCurrentInfohash()
	}

	// External listener
	conChan, listenPort, err := listenForPeerConnections([]byte(shareID.Psk[:]))
	if err != nil {
		log.Fatal("Couldn't listen for peers connection: ", err)
	}

	var currentSession TorrentSessionI = EmptyTorrent{}

	// quitChan
	quitChan := listenSigInt()

	// LPD
	lpd := &Announcer{announces: make(chan *Announce)}
	if useLPD {
		lpd, err = NewAnnouncer(listenPort)
		if err != nil {
			log.Fatal("Couldn't listen for Local Peer Discoveries: ", err)
		}
	}

	// Control session
	controlSession, err := NewControlSession(shareID, listenPort, session, trackers)
	if err != nil {
		log.Fatal(err)
	}
	if useLPD {
		lpd.Announce(string(shareID.Infohash))
	}
	for _, peer := range manualPeers {
		controlSession.backoffHintNewPeer(peer)
	}

	peers := session.GetPeers()
	for _, p := range peers {
		log.Printf("Feeding with known peer: %s\n", p)
		controlSession.backoffHintNewPeer(p)
	}

	log.Println("Starting.")

mainLoop:
	for {
		select {
		case <-quitChan:
			err := currentSession.Quit()
			if err != nil {
				log.Println("Failed: ", err)
			} else {
				log.Println("Done")
			}
			break mainLoop
		case c := <-conChan:
			if currentSession.Matches(c.infohash) {
				currentSession.AcceptNewPeer(c)
			} else if controlSession.Matches(c.infohash) {
				controlSession.AcceptNewPeer(c)
			}
		case announce := <-lpd.announces:
			hexhash, err := hex.DecodeString(announce.infohash)
			if err != nil {
				log.Println("Err with hex-decoding:", err)
				break
			}
			if controlSession.Matches(string(hexhash)) {
				controlSession.backoffHintNewPeer(announce.peer)
			}
		case ih := <-watcher.PingNewTorrent:
			if ih == controlSession.currentIH && !currentSession.IsEmpty() {
				break
			}
			err := controlSession.SetCurrent(ih)
			if err != nil {
				log.Fatal("Error setting new current infohash:", err)
			}

			currentSession.Quit()

			torrentFile := session.GetCurrentTorrent()
			tentativeSession, err := NewTorrentSession(shareID, target, torrentFile, listenPort)
			if err != nil {
				if !os.IsNotExist(err) {
					log.Println("Couldn't start new session from watched dir: ", err)
				}

				// Fallback to an emptytorrent, because the previous one is
				// invalid; hope it will be ok next time !
				currentSession = EmptyTorrent{}
				break
			}
			currentSession = tentativeSession
			go currentSession.DoTorrent()

			for _, peer := range controlSession.peers.All() {
				currentSession.hintNewPeer(peer.address)
			}
		case announce := <-controlSession.Torrents:
			if controlSession.currentIH == announce.infohash && !currentSession.IsEmpty() {
				break
			}
			err := controlSession.SetCurrent(announce.infohash)
			if err != nil {
				log.Fatal("Error setting new current infohash:", err)
			}

			currentSession.Quit()

			log.Println("Opening new torrent session")
			magnet := fmt.Sprintf("magnet:?xt=urn:btih:%x", announce.infohash)
			tentativeSession, err := NewTorrentSession(shareID, target, magnet, listenPort)
			if err != nil {
				log.Println("Couldn't start new session from announce: ", err)
				currentSession = EmptyTorrent{}
				break
			}
			currentSession = tentativeSession
			go currentSession.DoTorrent()
			currentSession.hintNewPeer(announce.peer)
		case peer := <-controlSession.NewPeers:
			if currentSession.IsEmpty() {
				magnet := fmt.Sprintf("magnet:?xt=urn:btih:%x", controlSession.currentIH)
				tentativeSession, err := NewTorrentSession(shareID, target, magnet, listenPort)
				if err != nil {
					log.Printf("Couldn't start new session with new peer: %s\n", err)
					break
				}
				currentSession = tentativeSession
				go currentSession.DoTorrent()
			}
			currentSession.hintNewPeer(peer)
		case meta := <-currentSession.NewMetaInfo():
			var buf bytes.Buffer
			err := bencode.NewEncoder(&buf).Encode(meta)
			if err != nil {
				log.Println(err)
				break
			}
			session.SaveTorrent(buf.Bytes(), meta.InfoHash, time.Now().Format(time.RFC3339))
		}
	}
}
Example #25
0
// Tries to call 'procedure' on remote node, with supplied 'args' and allocated return values 'reply'.
// 'timeout' can be used to specify a maximum time to wait for a reply (in seconds). If timeout is 0, we wait forever.
// The reliability of this completing successfully is dependent on the network protocol (UDP is unreliable)
// Returns an error if there is a timeout
func (node *Node) Call(procedure string, addr net.Addr, args interface{}, reply interface{}, timeout int) (err error) {
	// Get our call, which contains the message ID
	call := node.nextCall(addr)

	// Create Query
	query := Query{ProcedureName: procedure, MessageID: call.MessageID}
	query.constructArgs(args)

	// Create Message
	message := Message{Query: &query}

	// Encode it into BEncode
	buf := new(bytes.Buffer)
	bencodeE := bencode.NewEncoder(buf)
	if err := bencodeE.Encode(message); err != nil {
		fmt.Errorf("qrp:", "Error encoding query message into BEncode: %s\n", err.Error())
		return err
	}

	buf_bigEndian, err := encodeIntoBigEndian(buf)
	if err != nil {
		fmt.Errorf("qrp:", "Error encoding query message into BigEndian: %s\n", err.Error())
		return err
	}

	// Create channel for receiving response
	responseChan := make(responseChannel)

	// Allocate channel
	node.pendingMutex.Lock()
	node.pending[call] = &responseChan
	node.pendingMutex.Unlock()

	// Delete channel after exit
	defer func() {
		node.pendingMutex.Lock()
		delete(node.pending, call)
		node.pendingMutex.Unlock()
	}()

	// Send to host
	node.sendingMutex.Lock()
	node.connection.WriteTo(buf_bigEndian, addr)
	node.sendingMutex.Unlock()

	// If timeout isn't 0, initate the timeout function concurrently
	timeoutChan := make(chan bool, 1)
	if timeout > 0 {
		go func() {
			// Timeout function
			time.Sleep(time.Duration(timeout) * time.Second)
			timeoutChan <- true
		}()
	}

	// Wait for response on channel
	select {
	case replydata := <-responseChan:
		// We received a reply
		// Decode args
		argsReader := bytes.NewReader(replydata)
		argsDecoder := bencode.NewDecoder(argsReader)
		err := argsDecoder.Decode(reply)
		if err != nil {
			fmt.Errorf("qrp:", "Error decoding reply return data into value: %s\n", err.Error())
			return err
		}
	case <-timeoutChan:
		// We timed out
		return new(TimeoutError)
	}

	return nil
}
Example #26
0
func createMeta(dir string) (meta *MetaInfo, err error) {
	blockSize := int64(1 << 20) // 1MiB

	fileDicts := make([]*FileDict, 0)

	hasher := NewBlockHasher(blockSize)
	err = torrentWalk(dir, func(path string, info os.FileInfo, perr error) (err error) {
		if perr != nil {
			return perr
		}

		f, err := os.Open(path)
		if err != nil {
			return errors.New(fmt.Sprintf("Couldn't open %s for hashing: %s\n", path, err))
		}
		defer f.Close()

		_, err = io.Copy(hasher, f)
		if err != nil {
			log.Printf("Couldn't hash %s: %s\n", path, err)
			return err
		}

		relPath, err := filepath.Rel(dir, path)
		if err != nil {
			return
		}

		fileDict := &FileDict{
			Length: info.Size(),
			Path:   strings.Split(relPath, string(os.PathSeparator)),
		}
		fileDicts = append(fileDicts, fileDict)

		return
	})
	if err != nil {
		return
	}

	end := hasher.Close()
	if end != nil {
		return
	}

	meta = &MetaInfo{
		Info: &InfoDict{
			Pieces:      string(hasher.Pieces),
			PieceLength: blockSize,
			Private:     0,
			Name:        "rakoshare",
			Files:       fileDicts,
		},
	}

	hash := sha1.New()
	err = bencode.NewEncoder(hash).Encode(meta.Info)
	if err != nil {
		return
	}
	meta.InfoHash = string(hash.Sum(nil))

	return
}