示例#1
0
文件: main.go 项目: jbitor/cli
func cmdJsonFromBencoding(args []string) {
	if len(args) != 0 {
		logger.Fatalf("Usage: %v from-bencoding < FOO.torrent > FOO.bittorrent.json", os.Args[0])
		return
	}

	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		logger.Fatalf("Error reading stdin: %v", err)
		return
	}

	decoded, err := bencoding.Decode(data)
	if err != nil {
		logger.Fatalf("Error bdecoding stdin: %v", err)
		return
	}

	jsonable, err := decoded.ToJsonable()
	if err != nil {
		logger.Fatalf("Error converting bencoded value to jsonable: %v", err)
	}

	jsoned, err := json.Marshal(jsonable)
	if err != nil {
		logger.Fatalf("Error json-encoding data: %v", err)
		return
	}

	os.Stdout.Write(jsoned)
	os.Stdout.Sync()
}
示例#2
0
func (s *swarm) SetInfo(info []byte) (err error) {
	hashData := sha1.Sum(info)
	hash := string(hashData[:])
	if s.InfoHash() == BTID(hash) {
		info, _ := bencoding.Decode(info)
		s.info = info.(bencoding.Dict)
		logger.Info("Validated full info for torrent! %v", s)
		return nil
	} else {
		logger.Error("Infohash invalid: %v expected != %v actual", s.InfoHash(), BTID(hash))
		return errors.New("info hash was invalid")
	}
}
示例#3
0
文件: rpc.go 项目: jbitor/bittorrent
func (local *localNode) rpcListenLoop(terminate <-chan bool) {
	response := new([1024]byte)

	for {
		logger.Info("Waiting for next incoming UDP message.")

		n, remoteAddr, err := local.Connection.ReadFromUDP(response[:])

		_ = remoteAddr

		if err != nil {
			logger.Info("Ignoring UDP read err: %v", err)
			continue
		}

		result, err := bencoding.Decode(response[:n])

		if err != nil {
			logger.Info("Ignoring un-bedecodable message: %v", err)
			continue
		}

		resultD, ok := result.(bencoding.Dict)

		if !ok {
			logger.Info("Ignoring bedecoded non-dict message: %v", err)
			continue
		}

		transactionId := string(resultD["t"].(bencoding.String))

		query, ok := local.OutstandingQueries[transactionId]
		if !ok {
			logger.Info("Ignoring query response with unexpected token.")
			continue
		}

		query.Remote.LastResponseFrom = time.Now()

		resultBody, ok := resultD["r"].(bencoding.Dict)
		if !ok {
			logger.Info("Ignoring response with non-dict contents.")
			continue
		}

		query.Result <- &resultBody

		delete(local.OutstandingQueries, transactionId)
	}
}
示例#4
0
文件: peer.go 项目: jbitor/bittorrent
func (p *swarmPeer) onExtensionMessage(body string) {
	if len(body) == 0 {
		logger.Warning("got extension message with 0-length body -- what?!")
		return
	}

	extensionId := body[0]

	// TODO: A more sensible generic way of handling extensions and extension mesages
	if extensionId == 0 {
		// Handshake!
		logger.Info("Got an extension handshake message")

		bencoded := body[1:]
		data, err := bencoding.Decode([]byte(bencoded))

		if err != nil {
			logger.Error("Error decoding message: %v", err)
			return
		}

		// Check if the peer supports metadata exchange
		if dataM, hasM := data.(bencoding.Dict)["m"]; hasM {
			if mdxIdP, hasMdx := dataM.(bencoding.Dict)["ut_metadata"]; hasMdx {
				mdxId := uint8(mdxIdP.(bencoding.Int))

				if mdxId != 0 {
					logger.Info("Peer %v supports metadata exchange, using extension ID %v.", p, mdxId)
					p.extensions.bep9MetadataExchange.supported = true
					p.extensions.bep9MetadataExchange.id = mdxId
					go p.requestNextMetadataPiece()
				} else {
					logger.Info("Peer %v does not support metadata exchange!", p)
					return
				}
			} else {
				logger.Info("Peer %v does not support metadata exchange!", p)
				return
			}
		} else {
			logger.Info("Peer %v does not support metadata exchange!", p)
			return
		}
	} else if p.extensions.bep9MetadataExchange.supported && extensionId == ourUtMetadataId {
		p.onMdxMessage(body[1:])
	} else {
		logger.Warning("got extension message for unrecognied extension id %v from %v: %v", extensionId, p, body[1:])
	}
}
示例#5
0
/*
OpenClient instantiates a client whose state will be persisted at the specified path.

Existing state will be loaded if it exists, otherwise a new client will
be generated using a node a randomly-selected ID and port.

A filesystem lock will be used to ensure that only one Client may be open with
a given path at a time. The blocking parameter determines whether we block or
return an error when another Client is using the path.
*/
func OpenClient(path string, blocking bool) (c Client, err error) {
	var (
		openDataFile   *os.File
		nodeData       []byte
		nodeDict       bencoding.Bencodable
		nodeDictAsDict bencoding.Dict
		ok             bool
		lc             *localNodeClient
	)

	lc = new(localNodeClient)

	openDataFile, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return
	}
	lc.openDataFile = openDataFile

	flockMode := syscall.LOCK_EX

	if !blocking {
		flockMode |= syscall.LOCK_NB
	}

	err = syscall.Flock(int(openDataFile.Fd()), flockMode)
	if err != nil {
		return
	}

	nodeData, err = ioutil.ReadAll(lc.openDataFile)
	if err != nil {
		logger.Info("Unable to read existing DHT node file (%v). Creating a new one.", err)
		lc.localNode = newLocalNode()
	} else if len(nodeData) == 0 {
		logger.Info("Existing DHT node file was empty. Creating a new one.")
		lc.localNode = newLocalNode()
	} else {
		nodeDict, err = bencoding.Decode(nodeData)
		if err != nil {
			openDataFile.Close()
			return
		}

		nodeDictAsDict, ok = nodeDict.(bencoding.Dict)
		if !ok {
			err = errors.New("Node data wasn't a dict.")
			logger.Info("%v", err)
			openDataFile.Close()
			return
		}

		lc.localNode = localNodeFromBencodingDict(nodeDictAsDict)
		logger.Info("Loaded local node info from %v.", path)
	}

	terminateLocalNode := make(chan bool)
	lc.terminateLocalNode = terminateLocalNode

	c = Client(lc)

	err = lc.Run(terminateLocalNode)
	if err != nil {
		return
	}

	go func() {
		for lc.localNode != nil {
			c.Save()
			time.Sleep(15 * time.Second)
		}
	}()

	return
}