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(¤tIHMessage) if err != nil { cs.log("Error deserializing current ih message to be resent", err) } else { p.sendExtensionMessage("bs_metadata", currentIHMessage) } } return nil }
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(¤tIhMessage) 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 }
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 }
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() }
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 }
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 }
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 }
// 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) }
// 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 }
// 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 }
// 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 }
// 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 }
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 }