Пример #1
0
func (cs *ControlSession) DoHandshake(msg []byte, p *peerState) (err error) {
	var h ExtensionHandshake
	err = bencode.NewDecoder(bytes.NewReader(msg[1:])).Decode(&h)
	if err != nil {
		cs.log("Error when unmarshaling extension handshake")
		return err
	}

	p.theirExtensions = make(map[string]int)
	for name, code := range h.M {
		p.theirExtensions[name] = code
	}

	// Now that handshake is done and we know their extension, send the
	// current ih message, if we have one
	//
	// We need to de-serialize the current ih message saved in db before
	// passing it to the sender otherwise it is serialized into a string
	var currentIHMessage IHMessage
	currentFromSession := cs.session.GetCurrentIHMessage()
	if len(currentFromSession) > 0 {
		err = bencode.NewDecoder(strings.NewReader(currentFromSession)).Decode(&currentIHMessage)
		if err != nil {
			cs.log("Error deserializing current ih message to be resent", err)
		} else {
			p.sendExtensionMessage("bs_metadata", currentIHMessage)
		}
	}

	return nil
}
Пример #2
0
func NewControlSession(shareid id.Id, listenPort int, session *sharesession.Session, trackers []string) (*ControlSession, error) {
	sid := "-tt" + strconv.Itoa(os.Getpid()) + "_" + strconv.FormatInt(rand.Int63(), 10)

	// TODO: UPnP UDP port mapping.
	cfg := dht.NewConfig()
	cfg.Port = listenPort
	cfg.NumTargetPeers = TARGET_NUM_PEERS

	dhtNode, err := dht.New(cfg)
	if err != nil {
		log.Fatal("DHT node creation error", err)
	}

	current := session.GetCurrentIHMessage()
	var currentIhMessage IHMessage
	err = bencode.NewDecoder(strings.NewReader(current)).Decode(&currentIhMessage)
	if err != nil {
		log.Printf("Couldn't decode current message, starting from scratch: %s\n", err)
	}

	rev := "0-"
	if currentIhMessage.Info.Rev != "" {
		parts := strings.Split(currentIhMessage.Info.Rev, "-")
		if len(parts) == 2 {
			if _, err := strconv.Atoi(parts[0]); err == nil {
				rev = currentIhMessage.Info.Rev
			}
		}
	}

	cs := &ControlSession{
		Port:            listenPort,
		PeerID:          sid[:20],
		ID:              shareid,
		Torrents:        make(chan Announce),
		NewPeers:        make(chan string),
		dht:             dhtNode,
		peerMessageChan: make(chan peerMessage),
		quit:            make(chan struct{}),
		ourExtensions: map[int]string{
			1: "ut_pex",
			2: "bs_metadata",
		},
		peers: newPeers(),

		currentIH: currentIhMessage.Info.InfoHash,
		rev:       rev,

		trackers: trackers,

		session: session,
	}
	go cs.dht.Run()
	cs.dht.PeersRequest(string(cs.ID.Infohash), true)

	go cs.Run()

	return cs, nil
}
Пример #3
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
}
Пример #4
0
func (t *TorrentSession) reload(info []byte) error {
	err := bencode.NewDecoder(bytes.NewReader(info)).Decode(&t.m.Info)
	if err != nil {
		log.Println("Error when reloading torrent: ", err)
		return err
	}

	t.miChan <- t.m
	return t.load()
}
Пример #5
0
func DecodeInfoDict(bencodedInfo []byte) (map[string]interface{}, error) {
	decodedMap := make(map[string]interface{})

	bencodedBuffer := bytes.NewBuffer(bencodedInfo)
	dec := bencode.NewDecoder(bencodedBuffer)

	if err := dec.Decode(&decodedMap); err != nil {
		return nil, err
	}

	return decodedMap, nil
}
Пример #6
0
func getTrackerInfo(url string) (tr *TrackerResponse, err error) {
	r, err := proxyHttpGet(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 = errors.New(reason)
		return
	}

	var tr2 TrackerResponse
	err = bencode.NewDecoder(r.Body).Decode(&tr2)
	r.Body.Close()
	if err != nil {
		return
	}

	// Decode peers
	if len(tr2.PeersRaw) > 0 {
		const peerLen = 6
		nPeers := len(tr2.PeersRaw) / peerLen
		// log.Println("Tracker gave us", nPeers, "peers")
		tr2.Peers = make([]string, nPeers)
		for i := 0; i < nPeers; i++ {
			peer := nettools.BinaryToDottedPort(tr2.PeersRaw[i*peerLen : (i+1)*peerLen])
			tr2.Peers[i/peerLen] = peer
		}
	}

	// Decode peers6

	if len(tr2.Peers6Raw) > 0 {
		const peerLen = 18
		nPeers := len(tr2.Peers6Raw) / peerLen
		// log.Println("Tracker gave us", nPeers, "IPv6 peers")
		tr2.Peers6 = make([]string, nPeers)
		for i := 0; i < nPeers; i++ {
			peerEntry := tr2.Peers6Raw[i*peerLen : (i+1)*peerLen]
			host := net.IP(peerEntry[0:16])
			port := int((uint(peerEntry[16]) << 8) | uint(peerEntry[17]))
			peer := net.JoinHostPort(host.String(), strconv.Itoa(port))
			tr2.Peers6[i] = peer
		}
	}

	tr = &tr2
	return
}
Пример #7
0
func (t *TorrentSession) DoExtension(msg []byte, p *peerState) (err error) {

	var h ExtensionHandshake
	if msg[0] == EXTENSION_HANDSHAKE {
		err = bencode.NewDecoder(bytes.NewReader(msg[1:])).Decode(&h)
		if err != nil {
			log.Println("Error when unmarshaling extension handshake")
			return err
		}

		p.theirExtensions = make(map[string]int)
		for name, code := range h.M {
			p.theirExtensions[name] = code
		}

		if t.si.HaveTorrent || t.si.ME != nil && t.si.ME.Transferring {
			return
		}

		// Fill metadata info
		if h.MetadataSize == 0 {
			log.Printf("Missing metadata_size argument, this is invalid.")
			return
		}

		nPieces := h.MetadataSize/METADATA_PIECE_SIZE + 1
		t.si.ME.Pieces = make([][]byte, nPieces)

		if _, ok := p.theirExtensions["ut_metadata"]; ok {
			t.si.ME.Transferring = true
			p.sendMetadataRequest(0)
		}

	} else if ext, ok := t.si.OurExtensions[int(msg[0])]; ok {
		switch ext {
		case "ut_metadata":
			t.DoMetadata(msg[1:], p)
		case "ut_pex":
			t.DoPex(msg[1:], p)
		default:
			log.Println("Unknown extension: ", ext)
		}
	} else {
		log.Println("Unknown extension: ", int(msg[0]))
	}

	return nil
}
Пример #8
0
// Processes received packets
func (node *Node) processPacket(data []byte, read int, addr net.Addr) error {
	data_bigEndian, err := decodeIntoBigEndian(bytes.NewBuffer(data))
	if err != nil {
		return err
	}

	// Unmarshal BigEndian BEncode into struct
	bencodeDecoder := bencode.NewDecoder(bytes.NewBuffer(data_bigEndian))
	var message Message
	if err := bencodeDecoder.Decode(&message); err != nil {
		return err
	}

	// Further processing
	return node.processMessage(&message, addr)
}
Пример #9
0
// Reads a torrent-file from the filesystem.
// TODO: Model will create torrent-file; obsoleting this.
func ReadFile(file multipart.File) *Torrent {
	fmt.Printf("reading file...")

	torrent := &Torrent{Info: &TorrentFile{}, peers: NewPeerMap()}

	decoder := bencode.NewDecoder(file)
	err := decoder.Decode(torrent.Info)
	if err != nil {
		fmt.Printf("error decoding torrent file: %s", err.Error())
	}

	metainfo := torrent.Info
	torrent.Info.Info["private"] = 1

	fmt.Printf("info[] hash: %x \n", metainfo.EncodeInfo())
	fmt.Printf("# of pieces (hashes): %d \n", len(metainfo.Info["pieces"].(string))/20)

	return torrent
}
Пример #10
0
// Wraps the command and arguments in a map[string]interface{}, then
// uses the given Conn to encode them directly to the wire. It sends
// authorization if it is supplied in the given CJDNS.
func (cjdns *CJDNS) Send(command string, args map[string]interface{}) (response map[string]interface{}) {
	// Exit if the command is not given.
	if command == "" {
		return
	}
	// Otherwise, create the map which will be used to encode the
	// message.
	message := make(map[string]interface{})

	if cjdns.cookie != "" && cjdns.password != "" {
		// If there is authentication involved, then use
		// "aq". Otherwise, "q".

		hash := sha256.New()
		hash.Write([]byte(cjdns.password + cjdns.cookie))

		message["aq"] = command
		message["args"] = args
		message["cookie"] = cjdns.cookie
		message["hash"] = hex.EncodeToString(hash.Sum(nil)) // as specified
		message["q"] = CommandAuth

		// Prepare the hash
		m, err := bencode.EncodeString(message)
		if err != nil {
			return
		}

		hash = sha256.New()
		hash.Write([]byte(m))
		message["hash"] = hex.EncodeToString(hash.Sum(nil))
	} else {
		message["q"] = command
	}

	m, err := bencode.EncodeString(message)
	if err == nil {
		io.WriteString(cjdns.Conn, m)
		bencode.NewDecoder(cjdns.Conn).Decode(&response)
	}
	return
}
Пример #11
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
}
Пример #12
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
}
Пример #13
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
}