Giter Club home page Giter Club logo

dht's People

Contributors

cenkalti avatar hollow avatar jackpal avatar kbytesys avatar mjgarton avatar nhelke avatar nictuku avatar nordicdyno avatar rkjdid avatar soul9 avatar spikebike avatar xsleonard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dht's Issues

go test doesn't work

Unless there's something that needs setup, go test doesn't work as I'd expect:

$ go test -v
=== RUN TestDHTLocal

It just hangs, or at least runs for a very long time.

PeersRequestResults contains invalid binary peer address

func example(d *dht.DHT) {  
        for r := range d.PeersRequestResults {
        for _, peers := range r {
            for _, p := range peers {
                dht.DecodePeerAddress(p) // can panic
            }
        }
    }
}

Has resulted in this error once, of many runs. I do not know how to replicate it.

panic: runtime error: index out of range

goroutine 12 [running]:
runtime.panic(0x6e11e0, 0xc8bdb7)
/home/steve/.gvm/gos/go1.2rc3/src/pkg/runtime/panic.c:266 +0xb6
github.com/nictuku/nettools.BinaryToDottedPort(0x0, 0x0, 0x7fe8d2aefe90, 0x7fe8d2aefe80)
/home/steve/.gvm/pkgsets/go1.2rc3/global/src/github.com/nictuku/nettools/addresses.go:10 +0x260
github.com/nictuku/dht.DecodePeerAddress(0x0, 0x0, 0x14, 0xc21063ab80)
/home/steve/.gvm/pkgsets/go1.2rc3/global/src/github.com/nictuku/dht/krpc.go:258 +0x31

WAY too much traffic.

I have a very simple code that uses DHT to send out 16 peer requests every few minutes.

To launch the DHT:
numTargetPeers = 64
dht, err := dht.NewDHTNode(port, numTargetPeers, false)

Yet after just 16 calls to dht.PeersRequest and a minute or so of run time I get:

"totalDroppedPackets": 0,
"totalFindNodeDupes": 224,
"totalGetPeersDupes": 734,
"totalKilledNodes": 10
"totalNodes": 3610,
"totalPacketsFromBlockedHosts": 0,
"totalPeers": 15,
"totalReachableNodes": 575,
"totalRecv": 689,
"totalRecvFindNode": 0,
"totalRecvFindNodeReply": 185,
"totalRecvGetPeers": 0,
"totalRecvGetPeersReply": 403,
"totalRecvPingReply": 5,
"totalSelfPromotions": 0,
"totalSent": 3183,
"totalSentFindNode": 254,
"totalSentGetPeers": 2520,
"totalSentPing": 5,

SentGetPeers = 2520 times? Total Nodes = 3610?

My scroll back buffer isn't even long enough for a single second of the logs sent to stdout, I'll include a few here:

[10/30/13 05:10:19] [TRAC] wasContactedRecently for ih=4af397b24852d5b8b3e8ff389aff79288af69172 in node [email protected]:9638 returned true
[10/30/13 05:10:19] [TRAC] wasContactedRecently for ih=4af397b24852d5b8b3e8ff389aff79288af69172 in node [email protected]:51413 returned true
[10/30/13 05:10:19] [TRAC] wasContactedRecently for ih=4af397b24852d5b8b3e8ff389aff79288af69172 in node [email protected]:39776 returned true
[10/30/13 05:10:19] [TRAC] wasContactedRecently for ih=4af397b24852d5b8b3e8ff389aff79288af69172 in node [email protected]:8045 returned trueexit status 2

Am I doing something wrong? Is the default some kind of mapping all the nodes on the DHT or similar? My understanding is that each dht.PeersRequest should do log(N) peer lookups (where N is the number of nodes in the DHT).

wrapper around Run() ?

I think there's a small issue regarding the dht.Run() function, it both contains an initialization phase, prone to error (listen fails), and the main loop which I think suggests that it should be run in a go routine, since the only other way out is dht.Stop() from another routine.

It makes the handling of the first error a bit tricky. It also leads to another trickiness : a call to dht.Port() method is prone to hanging if listen fails and we did not check Run()'s return value - at least a close(dht.portRequest) would be necessary I think

I'm not sure about the best way to handle this, or if you wish to change anything at all, ideally I think we should accept the main loop will be running in a routine, and go dht.loop() ourselves in there as a private function if initialization (listen) was successful - loop not giving any error. It would allow the main entry point to return everytime, so we know the dht is running, or not. A downside to this is that it will induce retro-compatibilities issues, since we cannot expect dht.Run() to block - maybe something like an alternate dht.Start(), with depreciation on Run ?

runtime: goroutine stack exceeds 1000000000-byte limit fatal error: stack overflow

I run the example code, and then :

Note that there are many bad nodes that reply to anything you ask.
Peers found:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x40e130, 0xe)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:547 +0x90
runtime.newstack()
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/stack.go:940 +0xb11
runtime.morestack()
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/asm_amd64.s:359 +0x7f

goroutine 24 [stack growth]:
runtime.mallocgc(0x10, 0x36a100, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/malloc.go:499 fp=0xc8402002c8 sp=0xc8402002c0
runtime.newobject(0x36a100, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/malloc.go:781 +0x42 fp=0xc8402002f0 sp=0xc8402002c8
runtime.convT2E(0x36a100, 0xc840200370, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/iface.go:140 +0x97 fp=0xc840200318 sp=0xc8402002f0
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0x9b fp=0xc8402003a0 sp=0xc840200318
github.com/nictuku/dht.(*InfoHash).String(0xc8258c74b0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402003d8 sp=0xc8402003a0
fmt.(*pp).handleMethods(0xc8258de4e0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402004b8 sp=0xc8402003d8
fmt.(*pp).printArg(0xc8258de4e0, 0x36a100, 0xc8258c74b0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840200640 sp=0xc8402004b8
fmt.(*pp).doPrintf(0xc8258de4e0, 0x3fca10, 0x2, 0xc840200a60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402009c8 sp=0xc840200640
fmt.Sprintf(0x3fca10, 0x2, 0xc840200a60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840200a18 sp=0xc8402009c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840200aa0 sp=0xc840200a18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c74a0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840200ad8 sp=0xc840200aa0
fmt.(*pp).handleMethods(0xc8258de410, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840200bb8 sp=0xc840200ad8
fmt.(*pp).printArg(0xc8258de410, 0x36a100, 0xc8258c74a0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840200d40 sp=0xc840200bb8
fmt.(*pp).doPrintf(0xc8258de410, 0x3fca10, 0x2, 0xc840201160, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402010c8 sp=0xc840200d40
fmt.Sprintf(0x3fca10, 0x2, 0xc840201160, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840201118 sp=0xc8402010c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402011a0 sp=0xc840201118
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7490, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402011d8 sp=0xc8402011a0
fmt.(*pp).handleMethods(0xc8258de340, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402012b8 sp=0xc8402011d8
fmt.(*pp).printArg(0xc8258de340, 0x36a100, 0xc8258c7490, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840201440 sp=0xc8402012b8
fmt.(*pp).doPrintf(0xc8258de340, 0x3fca10, 0x2, 0xc840201860, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402017c8 sp=0xc840201440
fmt.Sprintf(0x3fca10, 0x2, 0xc840201860, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840201818 sp=0xc8402017c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402018a0 sp=0xc840201818
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7480, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402018d8 sp=0xc8402018a0
fmt.(*pp).handleMethods(0xc8258de270, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402019b8 sp=0xc8402018d8
fmt.(*pp).printArg(0xc8258de270, 0x36a100, 0xc8258c7480, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840201b40 sp=0xc8402019b8
fmt.(*pp).doPrintf(0xc8258de270, 0x3fca10, 0x2, 0xc840201f60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840201ec8 sp=0xc840201b40
fmt.Sprintf(0x3fca10, 0x2, 0xc840201f60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840201f18 sp=0xc840201ec8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840201fa0 sp=0xc840201f18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7470, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840201fd8 sp=0xc840201fa0
fmt.(*pp).handleMethods(0xc8258de1a0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402020b8 sp=0xc840201fd8
fmt.(*pp).printArg(0xc8258de1a0, 0x36a100, 0xc8258c7470, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840202240 sp=0xc8402020b8
fmt.(*pp).doPrintf(0xc8258de1a0, 0x3fca10, 0x2, 0xc840202660, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402025c8 sp=0xc840202240
fmt.Sprintf(0x3fca10, 0x2, 0xc840202660, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840202618 sp=0xc8402025c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402026a0 sp=0xc840202618
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7460, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402026d8 sp=0xc8402026a0
fmt.(*pp).handleMethods(0xc8258de0d0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402027b8 sp=0xc8402026d8
fmt.(*pp).printArg(0xc8258de0d0, 0x36a100, 0xc8258c7460, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840202940 sp=0xc8402027b8
fmt.(*pp).doPrintf(0xc8258de0d0, 0x3fca10, 0x2, 0xc840202d60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840202cc8 sp=0xc840202940
fmt.Sprintf(0x3fca10, 0x2, 0xc840202d60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840202d18 sp=0xc840202cc8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840202da0 sp=0xc840202d18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7450, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840202dd8 sp=0xc840202da0
fmt.(*pp).handleMethods(0xc8258de000, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840202eb8 sp=0xc840202dd8
fmt.(*pp).printArg(0xc8258de000, 0x36a100, 0xc8258c7450, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840203040 sp=0xc840202eb8
fmt.(*pp).doPrintf(0xc8258de000, 0x3fca10, 0x2, 0xc840203460, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402033c8 sp=0xc840203040
fmt.Sprintf(0x3fca10, 0x2, 0xc840203460, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840203418 sp=0xc8402033c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402034a0 sp=0xc840203418
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7440, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402034d8 sp=0xc8402034a0
fmt.(*pp).handleMethods(0xc8258dbee0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402035b8 sp=0xc8402034d8
fmt.(*pp).printArg(0xc8258dbee0, 0x36a100, 0xc8258c7440, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840203740 sp=0xc8402035b8
fmt.(*pp).doPrintf(0xc8258dbee0, 0x3fca10, 0x2, 0xc840203b60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840203ac8 sp=0xc840203740
fmt.Sprintf(0x3fca10, 0x2, 0xc840203b60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840203b18 sp=0xc840203ac8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840203ba0 sp=0xc840203b18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7430, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840203bd8 sp=0xc840203ba0
fmt.(*pp).handleMethods(0xc8258dbe10, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840203cb8 sp=0xc840203bd8
fmt.(*pp).printArg(0xc8258dbe10, 0x36a100, 0xc8258c7430, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840203e40 sp=0xc840203cb8
fmt.(*pp).doPrintf(0xc8258dbe10, 0x3fca10, 0x2, 0xc840204260, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402041c8 sp=0xc840203e40
fmt.Sprintf(0x3fca10, 0x2, 0xc840204260, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840204218 sp=0xc8402041c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402042a0 sp=0xc840204218
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7420, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402042d8 sp=0xc8402042a0
fmt.(*pp).handleMethods(0xc8258dbd40, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402043b8 sp=0xc8402042d8
fmt.(*pp).printArg(0xc8258dbd40, 0x36a100, 0xc8258c7420, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840204540 sp=0xc8402043b8
fmt.(*pp).doPrintf(0xc8258dbd40, 0x3fca10, 0x2, 0xc840204960, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402048c8 sp=0xc840204540
fmt.Sprintf(0x3fca10, 0x2, 0xc840204960, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840204918 sp=0xc8402048c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402049a0 sp=0xc840204918
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7410, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402049d8 sp=0xc8402049a0
fmt.(*pp).handleMethods(0xc8258dbc70, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840204ab8 sp=0xc8402049d8
fmt.(*pp).printArg(0xc8258dbc70, 0x36a100, 0xc8258c7410, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840204c40 sp=0xc840204ab8
fmt.(*pp).doPrintf(0xc8258dbc70, 0x3fca10, 0x2, 0xc840205060, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840204fc8 sp=0xc840204c40
fmt.Sprintf(0x3fca10, 0x2, 0xc840205060, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840205018 sp=0xc840204fc8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402050a0 sp=0xc840205018
github.com/nictuku/dht.(*InfoHash).String(0xc8258c7400, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402050d8 sp=0xc8402050a0
fmt.(*pp).handleMethods(0xc8258dbba0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402051b8 sp=0xc8402050d8
fmt.(*pp).printArg(0xc8258dbba0, 0x36a100, 0xc8258c7400, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840205340 sp=0xc8402051b8
fmt.(*pp).doPrintf(0xc8258dbba0, 0x3fca10, 0x2, 0xc840205760, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402056c8 sp=0xc840205340
fmt.Sprintf(0x3fca10, 0x2, 0xc840205760, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840205718 sp=0xc8402056c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402057a0 sp=0xc840205718
github.com/nictuku/dht.(*InfoHash).String(0xc8258c73f0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402057d8 sp=0xc8402057a0
fmt.(*pp).handleMethods(0xc8258dbad0, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402058b8 sp=0xc8402057d8
fmt.(*pp).printArg(0xc8258dbad0, 0x36a100, 0xc8258c73f0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840205a40 sp=0xc8402058b8
fmt.(*pp).doPrintf(0xc8258dbad0, 0x3fca10, 0x2, 0xc840205e60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840205dc8 sp=0xc840205a40
fmt.Sprintf(0x3fca10, 0x2, 0xc840205e60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840205e18 sp=0xc840205dc8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840205ea0 sp=0xc840205e18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c73e0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840205ed8 sp=0xc840205ea0
fmt.(*pp).handleMethods(0xc8258dba00, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840205fb8 sp=0xc840205ed8
fmt.(*pp).printArg(0xc8258dba00, 0x36a100, 0xc8258c73e0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840206140 sp=0xc840205fb8
fmt.(*pp).doPrintf(0xc8258dba00, 0x3fca10, 0x2, 0xc840206560, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402064c8 sp=0xc840206140
fmt.Sprintf(0x3fca10, 0x2, 0xc840206560, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840206518 sp=0xc8402064c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402065a0 sp=0xc840206518
github.com/nictuku/dht.(*InfoHash).String(0xc8258c73d0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc8402065d8 sp=0xc8402065a0
fmt.(*pp).handleMethods(0xc8258db930, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc8402066b8 sp=0xc8402065d8
fmt.(*pp).printArg(0xc8258db930, 0x36a100, 0xc8258c73d0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840206840 sp=0xc8402066b8
fmt.(*pp).doPrintf(0xc8258db930, 0x3fca10, 0x2, 0xc840206c60, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc840206bc8 sp=0xc840206840
fmt.Sprintf(0x3fca10, 0x2, 0xc840206c60, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840206c18 sp=0xc840206bc8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc840206ca0 sp=0xc840206c18
github.com/nictuku/dht.(*InfoHash).String(0xc8258c73c0, 0x0, 0x0)
    <autogenerated>:3 +0xa4 fp=0xc840206cd8 sp=0xc840206ca0
fmt.(*pp).handleMethods(0xc8258db860, 0xc800000078, 0x0, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:730 +0x62a fp=0xc840206db8 sp=0xc840206cd8
fmt.(*pp).printArg(0xc8258db860, 0x36a100, 0xc8258c73c0, 0x78, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:806 +0x4a9 fp=0xc840206f40 sp=0xc840206db8
fmt.(*pp).doPrintf(0xc8258db860, 0x3fca10, 0x2, 0xc840207360, 0x1, 0x1)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:1238 +0x1dcd fp=0xc8402072c8 sp=0xc840206f40
fmt.Sprintf(0x3fca10, 0x2, 0xc840207360, 0x1, 0x1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/fmt/print.go:203 +0x6f fp=0xc840207318 sp=0xc8402072c8
github.com/nictuku/dht.InfoHash.String(0xc8200daba0, 0x14, 0x0, 0x0)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:277 +0xfb fp=0xc8402073a0 sp=0xc840207318
...additional frames elided...
created by github.com/nictuku/dht.(*DHT).Start
    /workspace/go/src/github.com/nictuku/dht/dht.go:319 +0x95

goroutine 1 [sleep]:
time.Sleep(0x12a05f200)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/time.go:59 +0xf9
main.main()
    /tongshe/tongshe-desktop/ssmm/p2p.go:65 +0x8f2

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/asm_amd64.s:1998 +0x1

goroutine 20 [chan receive]:
github.com/golang/glog.(*loggingT).flushDaemon(0x5e33a0)
    /workspace/go/src/github.com/golang/glog/glog.go:882 +0x67
created by github.com/golang/glog.init.1
    /workspace/go/src/github.com/golang/glog/glog.go:410 +0x297

goroutine 21 [select]:
github.com/nictuku/nettools.(*ClientThrottle).cleanup(0xc8200da9c0)
    /workspace/go/src/github.com/nictuku/nettools/ratelimit.go:78 +0x2ec
created by github.com/nictuku/nettools.NewThrottler
    /workspace/go/src/github.com/nictuku/nettools/ratelimit.go:19 +0x31a

goroutine 23 [IO wait]:
net.runtime_pollWait(0x1210fd8, 0x72, 0x1250028)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/netpoll.go:160 +0x60
net.(*pollDesc).Wait(0xc8200f8060, 0x72, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_poll_runtime.go:73 +0x3a
net.(*pollDesc).WaitRead(0xc8200f8060, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_poll_runtime.go:78 +0x36
net.(*netFD).accept(0xc8200f8000, 0x0, 0x12110d0, 0xc82000e1c0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_unix.go:426 +0x27c
net.(*TCPListener).AcceptTCP(0xc82002a010, 0xbf5b1, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/tcpsock_posix.go:254 +0x4d
net/http.tcpKeepAliveListener.Accept(0xc82002a010, 0x0, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2427 +0x41
net/http.(*Server).Serve(0xc8200f6000, 0x1211098, 0xc82002a010, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2117 +0x129
net/http.(*Server).ListenAndServe(0xc8200f6000, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2098 +0x136
net/http.ListenAndServe(0xc820071048, 0x5, 0x0, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2195 +0x98
created by main.main
    /tongshe/tongshe-desktop/ssmm/p2p.go:55 +0x74d

goroutine 25 [chan receive]:
main.drainresults(0xc8200a6280)
    /tongshe/tongshe-desktop/ssmm/p2p.go:76 +0x42c
created by main.main
    /tongshe/tongshe-desktop/ssmm/p2p.go:61 +0x8b8

goroutine 4 [IO wait]:
net.runtime_pollWait(0x1210f18, 0x72, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/netpoll.go:160 +0x60
net.(*pollDesc).Wait(0xc82006a450, 0x72, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_poll_runtime.go:73 +0x3a
net.(*pollDesc).WaitRead(0xc82006a450, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_poll_runtime.go:78 +0x36
net.(*netFD).readFrom(0xc82006a3f0, 0xc82014e000, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x1250028, 0xc8200700a0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/fd_unix.go:277 +0x2a5
net.(*UDPConn).ReadFromUDP(0xc820080050, 0xc82014e000, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/net/udpsock_posix.go:61 +0x117
github.com/nictuku/dht.readFromSocket(0xc820080050, 0xc8200e60c0, 0xc8200e6060, 0xc82006e240)
    /workspace/go/src/github.com/nictuku/dht/krpc.go:234 +0x100
github.com/nictuku/dht.(*DHT).loop.func1(0xc8200a6280, 0xc8200e60c0, 0xc8200e6060)
    /workspace/go/src/github.com/nictuku/dht/dht.go:386 +0x84
created by github.com/nictuku/dht.(*DHT).loop
    /workspace/go/src/github.com/nictuku/dht/dht.go:387 +0x135

Project has moved

code.google.com/p/bencode-go ==> github.com/jackpal/bencode-go
code.google.com/p/vitess/go/cache ==> github.com/youtube/vitess/go/cache

fix data race in node cleanup

WARNING: DATA RACE
Write by goroutine 52:
github.com/nictuku/dht.(_remoteNode).newQuery()
/Users/yves/go/src/pkg/github.com/nictuku/dht/krpc.go:88 +0x186
github.com/nictuku/dht.(_DHT).pingNode()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:414 +0x116
github.com/nictuku/dht.func·002()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:267 +0x105

Previous read by goroutine 10:
github.com/nictuku/dht.(_nTree).filter()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:224 +0x100
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:151 +0xf6
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:179 +0x480
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:179 +0x480
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:179 +0x480
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).traverse()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:175 +0x334
github.com/nictuku/dht.(_nTree).lookupFiltered()
/Users/yves/go/src/pkg/github.com/nictuku/dht/routing.go:143 +0x105
github.com/nictuku/dht.(_DHT).nodesForInfoHash()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:526 +0xd7
github.com/nictuku/dht.(_DHT).replyGetPeers()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:519 +0x5da
github.com/nictuku/dht.(_DHT).processPacket()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:390 +0x14f1
github.com/nictuku/dht.(*DHT).DoDHT()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:244 +0x84b

Goroutine 52 (running) created at:
github.com/nictuku/dht.(*DHT).DoDHT()
/Users/yves/go/src/pkg/github.com/nictuku/dht/dht.go:270 +0xa74

Goroutine 10 (running) created at:
main.main()
/Users/yves/go/src/github.com/nictuku/magnets/supernode/main.go:99 +0x3c5
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

Unexpected panic in TestDHTLarge: routingTable.insert() got a node with a nil address

This is not reliably reproduceable.

$ go test -v
=== RUN TestDHTLocal
Found peer 0: 127.0.0.1:52407
Found peer 0: 127.0.0.1:42450
--- PASS: TestDHTLocal (1.41 seconds)
=== RUN TestDHTLarge
panic: routingTable.insert() got a node with a nil address

goroutine 41 [running]:
runtime.panic(0x67d840, 0xc20815e100)
        /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/nictuku/dht.(*routingTable).insert(0xc2080a4ba0, 0xc20815ac00, 0x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/routing_table.go:122 +0x391
github.com/nictuku/dht.(*routingTable).getOrCreateNode(0xc2080a4ba0, 0xc208152000, 0x14, 0xc208169fe0, 0x10, 0xc20815ac0
0, 0x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/routing_table.go:162 +0x180
github.com/nictuku/dht.(*DHT).processFindNodeResults(0xc2080b2fc0, 0xc2080a2240, 0xc20816962a, 0x1, 0xc20816970a, 0x1, 0
x0, 0x0, 0x0, 0x0, ...)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:908 +0xa86
github.com/nictuku/dht.(*DHT).processPacket(0xc2080b2fc0, 0xc208121000, 0x11c, 0x1000, 0xc208141e88, 0x4, 0x4, 0x1ae1, 0
x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:518 +0xec7
github.com/nictuku/dht.(*DHT).Run(0xc2080b2fc0, 0x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:385 +0xca4
created by github.com/nictuku/dht.TestDHTLarge 
        /home/nictuku/src/github.com/nictuku/dht/dht_test.go:178 +0x2cf

goroutine 16 [chan receive]:
testing.RunTests(0x7ff570, 0x91ff60, 0xa, 0xa, 0x1)
        /usr/local/go/src/pkg/testing/testing.go:505 +0x923
testing.Main(0x7ff570, 0x91ff60, 0xa, 0xa, 0x91e720, 0x3, 0x3, 0x91b0a0, 0x1, 0x1)
        /usr/local/go/src/pkg/testing/testing.go:435 +0x84
main.main()
        github.com/nictuku/dht/_test/_testmain.go:73 +0x9c

Add a version string to all outgoing messages

BEP 5 has been updated to document the long standing de-facto standard of including a version string in RPC messages. This is an important feature for identifying implementations which may be lacking features or misbehaving. The relevant section of BEP5:

A key v should be included in every message with a client version string. The string should be a two character client identifier registered in BEP 20 followed by a two character version identifier.

The convention is for the client identifier to identify the DHT implementation rather than the client application. Thus the same identifier should be used regardless of which client is using this module.

Enable Sourcegraph

Hey, this is Bill Broadley. Was using sourcegraph to look at DHT for the pending IPv6 patches. Seems harmless (and free) to enable sourcegraph to rebuild after each commit. Just a though, thanks.

I want to use Sourcegraph code search and code review with dht. A project maintainer needs to enable it to set up a webhook so the code is up-to-date there.

Could you please enable dht on @sourcegraph by going to https://sourcegraph.com/github.com/nictuku/dht and clicking on Settings? (It should only take 15 seconds.)

Thank you!

PeerStore Ring Move? Possible Bug?

When I looked at the code of peerContactsSet, this function seems to be wrong.

func (p *peerContactsSet) next() []string {
	count := kNodes
	if count > len(p.set) {
		count = len(p.set)
	}
	x := make([]string, 0, count)
	xx := make(map[string]bool) //maps are easier to dedupe
	for range p.set {
		nid := p.ring.Move(1).Value.(string)  <----this line will always return the first next item since p.ring never change its pos.
		if _, ok := xx[nid]; p.set[nid] && !ok {
			xx[nid] = true
		}
		if len(xx) >= count {
			break
		}
	}
...

The move function will return a new pointer rather than change the original pointer as demonstrated in this playground.

func (r *Ring) Move(n int) *Ring {
	if r.next == nil {
		return r.init()
	}
	switch {
	case n < 0:
		for ; n < 0; n++ {
			r = r.prev
		}
	case n > 0:
		for ; n > 0; n-- {
			r = r.next
		}
	}
	return r
}

Need a PR to fix it?

Dependencies

In your project, you use github.com/youtube/vitess/go/cache and github.com/golang/groupcache/lru.
These dependencies are HUGE and you only need a small part.
You should copy them and create a small repository, like https://github.com/pierrre/lrucache .

When I run the example(main.go), I catch this error.

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0xb9db6]

goroutine 10 [running]:
github.com/nictuku/dht.(_routingTable).kill(0xc20803cb10, 0xc2080980c0)
/Users/yuansc/go/src/github.com/nictuku/dht/routing_table.go:176 +0x136
github.com/nictuku/dht.(_routingTable).cleanup(0xc20803cb10, 0xd18c2e2800, 0xc20802e3c0, 0x0, 0xa)
/Users/yuansc/go/src/github.com/nictuku/dht/routing_table.go:228 +0x8d3
github.com/nictuku/dht.(*DHT).Run(0xc20804e140, 0x0, 0x0)
/Users/yuansc/go/src/github.com/nictuku/dht/dht.go:412 +0x1045
created by main.main
/Users/yuansc/go/src/dht/examples/find_infohash_and_wait/main.go:57 +0x783

goroutine 1 [sleep]:
main.main()
/Users/yuansc/go/src/dht/examples/find_infohash_and_wait/main.go:65 +0x923

goroutine 5 [chan receive]:
github.com/golang/glog.(*loggingT).flushDaemon(0x4a0b00)
/Users/yuansc/go/src/github.com/golang/glog/glog.go:879 +0x78
created by github.com/golang/glog.init·1
/Users/yuansc/go/src/github.com/golang/glog/glog.go:410 +0x2a7

goroutine 17 [syscall, 45 minutes, locked to thread]:
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2232 +0x1

goroutine 7 [select]:
github.com/nictuku/nettools.(*ClientThrottle).cleanup(0xc20800ab20)
/Users/yuansc/go/src/github.com/nictuku/nettools/ratelimit.go:78 +0x28b
created by github.com/nictuku/nettools.NewThrottler
/Users/yuansc/go/src/github.com/nictuku/nettools/ratelimit.go:19 +0xe8

goroutine 12 [IO wait, 43 minutes]:
net.(_pollDesc).Wait(0xc208010220, 0x72, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:84 +0x47
net.(_pollDesc).WaitRead(0xc208010220, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:89 +0x43
net.(_netFD).readFrom(0xc2080101c0, 0xc208094000, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x566b48, 0xc20802aa10)
/usr/local/go/src/net/fd_unix.go:269 +0x4a1
net.(_UDPConn).ReadFromUDP(0xc20802c050, 0xc208094000, 0x1000, 0x1000, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/udpsock_posix.go:67 +0x124
github.com/nictuku/dht.readFromSocket(0xc20802c050, 0xc208050540, 0xc2080505a0, 0xc208050180)
/Users/yuansc/go/src/github.com/nictuku/dht/krpc.go:231 +0xff
created by github.com/nictuku/dht.(*DHT).Run
/Users/yuansc/go/src/github.com/nictuku/dht/dht.go:307 +0x1eb

goroutine 9 [IO wait, 43 minutes]:
net.(_pollDesc).Wait(0xc2080101b0, 0x72, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:84 +0x47
net.(_pollDesc).WaitRead(0xc2080101b0, 0x0, 0x0)
/usr/local/go/src/net/fd_poll_runtime.go:89 +0x43
net.(_netFD).accept(0xc208010150, 0x0, 0x566b48, 0xc20802a950)
/usr/local/go/src/net/fd_unix.go:419 +0x40b
net.(_TCPListener).AcceptTCP(0xc20802c048, 0x70cc4, 0x0, 0x0)
/usr/local/go/src/net/tcpsock_posix.go:234 +0x4e
net/http.tcpKeepAliveListener.Accept(0xc20802c048, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1976 +0x4c
net/http.(_Server).Serve(0xc2080504e0, 0x568200, 0xc20802c048, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1728 +0x92
net/http.(_Server).ListenAndServe(0xc2080504e0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1718 +0x154
net/http.ListenAndServe(0xc20802a910, 0x5, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:1808 +0xba
created by main.main
/Users/yuansc/go/src/dht/examples/find_infohash_and_wait/main.go:55 +0x769

goroutine 11 [chan receive, 43 minutes]:
main.drainresults(0xc20804e140)
/Users/yuansc/go/src/dht/examples/find_infohash_and_wait/main.go:75 +0x32d
created by main.main
/Users/yuansc/go/src/dht/examples/find_infohash_and_wait/main.go:58 +0x79d
exit status 2
yuansc@/go/src/dht/examples/find_infohash_and_wait:$
yuansc@
/go/src/dht/examples/find_infohash_and_wait:$ go run main.go deca7a89a1dbdc4b213de1c0d5351e92582f31fb

panic in dht neighborhoodUpkeep calling comonBits

panic: runtime error: index out of range

goroutine 1064 [running]:
runtime.panic(0x73b980, 0xba1337)
/usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
github.com/nictuku/dht.commonBits(0xc2109e8fe0, 0x14, 0x0, 0x0, 0xc22ea73680)
/home/nictuku/src/github.com/nictuku/dht/routing.go:241 +0x15f
github.com/nictuku/dht.(_routingTable).neighborhoodUpkeep(0xc210f0cf60, 0xc213537b80)
/home/nictuku/src/github.com/nictuku/dht/routing_table.go:248 +0xa6
github.com/nictuku/dht.(_DHT).processPacket(0xc210fdcf00, 0xc211512000, 0x41, 0x1000, 0xc2308810f0)
/home/nictuku/src/github.com/nictuku/dht/dht.go:476 +0x6a0
github.com/nictuku/dht.(_DHT).Run(0xc210fdcf00, 0x0, 0x0)
/home/nictuku/src/github.com/nictuku/dht/dht.go:374 +0x9ee
github.com/nictuku/dht.(_DHT).DoDHT(0xc210fdcf00)
/home/nictuku/src/github.com/nictuku/dht/deprecated.go:5 +0x27
created by main.main
/home/nictuku/src/github.com/nictuku/magnets/supernode/main.go:127 +0x773

Callback when infohashes are seen

I have recently been using Popcorn Time a lot, and I like the features but dislike the build quality.

So I started thinking about how one could build something similar, but more robust. The first improvement, of course, would be to build it in Go instead of JavaScript.

Another would be to use some other search/browse database than whatever Popcorn Time uses (which isn't very robust at all).

Finally I found https://www.usenix.org/legacy/event/woot10/tech/full_papers/Wolchok.pdf, which describes how to seed the network with pure forwarding nodes that only tap the infohashes it sees in those nodes, and then fetch the metadata from the hosting nodes to put them in a local searchable database.

This made me start looking at your code. Unfortunately I get confused by it - I am used to chord-style networks, and kademlia is like greek to me :)

Where should I add code to enable some kind of callback function whenever the node gets queried about an infohash?

Some way to classify peers.

This DHT/BEP-0005 is a great way to find peers for any p2p program, not just torrent clients.

Of course if you aren't a bit-torrent client you likely want to find other similar peers. This would be trivial without evil peers that reply to any infohash. So you could just make an infohash from "I am p2p peer foo version 1.2.3x" and anyone else with that string could find you. Alas some peers will respond to any infohash request.

Can you think of any response from the supported commands that would help differentiate peers? Any idea how different bit-torrent clients that support unique functionality with peers running the same software detect each other? I'm trying to avoid just trying to connect to some socket because of complications for end users to forward extra ports through routers and the like.

A similar Kademlia implementation mentions families at:
https://github.com/telehash/telehash.org/blob/master/protocol.md#family-usage

Sounds ideal:

  • You can use all peers to help find someone in your family
  • Once you find family peers you reserve half off each bucket for peers in your family
  • increased resistance to malicious peers, flooding, and Sybil attacks.

I realize this may be outside the intended scope, but I figured it's worth mentioning just in case.

Is it possible to use this library for DHT router ?

It's not clear about possibility to build a DHT router on this library.
It seems that this is possible, because in dht_test.go there is a test TestDHTLocal that seems testing exact same case. But it also looks like test itself is incorrect.
If add little bit more logging to it, then output will be

n1 started at port 52361
n2 started at port 52604
n3 started at port 57136
Node n3 found a peer 0: 127.0.0.1:57136
Node n2 found a peer 0: 127.0.0.1:52604

It looks like node found itself as a peer instead of finding at least one more node.
Do I understand meaning of the test correctly? Is it possible after all to use this library for building DHT router?

high memory usage under heavy load

was running about 5 hours with that settings ... filling in 1000 searches/hashes in parallel and immediately refill it...

I've used a slightly modified dht.go because I had disabled the clientThrottle feature for debugging reason. so use that one regarding line numbers.

                      s, err = dht.New(&dht.Config{
                                Address:                 "",
                                Port:                    sPort,
                                NumTargetPeers:          5000,
                                DHTRouters:              "router.magnets.im:6881,router.bittorrent.com:6881,dht.transmissionbt.com:6881,router.utorrent.com:6881,dht.aelitis.com:6881,dht.libtorrent.org:25401",
                                MaxNodes:                500,
                               CleanupPeriod:           3 * time.Minute,
                                SaveRoutingTable:        false,
                                RateLimit:               -1,
                                MaxInfoHashes:           2,
                                MaxInfoHashPeers:        2,
                                ClientPerMinuteLimit:    50,
                                ThrottlerTrackedClients: 10,
                                UDPProto:                "udp4",

heap2

more detailed

heap2_detail

it seems 2.5gig of the 8 get’s eaten by dht.go:610 which is
node.pastQueries[r.T] = query

also in krpc.go:189 the jackpal unmarshal eats another 1.123gig


CPU looks fine to me, just the unmarshal eats a plenty.. after I got (and still see) many of dht.go:568] DHT: readResponse Error: unexpected EOF, I was trying to replace it with https://github.com/IncSW/go-bencode (with is much less cpu intensive regarding the benchmarks there) to see if it solves the issue, but due to my very limited golang skills I was unable to find the right syntax parameters and value type conversations to make it work.

cpu


time


expvar output

Proposal/Feature request: Add IPv6 support.

One of the harder parts of P2P is dealing with IP Masq/NAT'd peers. Fortunately there's an awesome fix, IPv6. Google claims 9.85% of Google's traffic in the USA is from IPv6 users, far from a trivial number. I've managed to get IPv6 connectivity working at 2 locations so I can tinker. Comcast is giving out /60's to regular home users!

I'm going to take a shot at it. I've not written any IPv6 code before though.

The resources I'm referencing are https://github.com/jech/dht and http://www.bittorrent.org/beps/bep_0032.html.

Just figured I'd post here in case anyone else is interested or planning similar.

Disable some/all logging output

I am using dht as a library in my application and I don't want it to print any log statements to the output. The output of dht library does not make sense to the user of my application.

There are messages showing as

ERROR: logging before flag.Parse: W1103 08:59:46.124232   26525 dht.go:566] DHT: readResponse Error: unexpected EOF, "d1:rd2:id20:d\xe9ᢇN>\r\x03-\xc8t\xcd\xfc\xca\x15L.\xe6D5:nodes4368:...

in the output of my program. There are 2 issues that causes this:

  • glog requires flag.Parse() to be called before logging any output. My program does not call flag.Parse().
  • dht logs at level zero (V(0)).

IMO, a good library must not print any output and should provide a way of returning internal events and errors. I propose removing glog from this library and take a logger implementation from outside that implements dht.Logger interface. I can provide a PR for this if you are OK with the idea.

If you don't want to remove glog, for just solving the output problem, we can replace direct calls to glog.Info and glog.Warning functions into glog.V(1).Info calls. In other words, do not log output at level 0. I can provide a PR for this too.

@nictuku what do you think?

crash in nodesForInfoHash()

panic: runtime error: slice bounds out of range

goroutine 18 [running]:
github.com/nictuku/nettools.DottedPortToBinary(0xc200e0f5a0, 0x1c, 0x1c, 0xc200ece978)
/home/nictuku/src/github.com/nictuku/nettools/addresses.go:25 +0x404
github.com/nictuku/dht.(_DHT).nodesForInfoHash(0xc20010f380, 0xc200e15f40, 0x14, 0x0, 0x0, ...)
/home/nictuku/src/github.com/nictuku/dht/dht.go:525 +0x17a
github.com/nictuku/dht.(_DHT).replyGetPeers(0xc20010f380, 0xc200e20840, 0xc200ece600, 0x4, 0xc200ece748, ...)
/home/nictuku/src/github.com/nictuku/dht/dht.go:515 +0x62d
github.com/nictuku/dht.(_DHT).processPacket(0xc20010f380, 0xc20081d000, 0x6a, 0x1000, 0xc200e20840, ...)
/home/nictuku/src/github.com/nictuku/dht/dht.go:383 +0x1449
github.com/nictuku/dht.(_DHT).DoDHT(0xc20010f380)
/home/nictuku/src/github.com/nictuku/dht/dht.go:252 +0x8f4
created by main.main
/home/nictuku/src/github.com/nictuku/magnets/supernode/main.go:119 +0x8d9

stop sending dupe find_node queries to the same nodes

nictuku@1:~/src/github.com/nictuku/dht/examples/find_infohash_and_wait$ ./find_infohash_and_wait b04eeb70b231286c47ae61840fc52153768dc83d > log

grep 6730962b722d07086c265c4f6261c73f3ee2f919 log

[03/25/13 00:37:10] [TRAC] DHT: Got new node reference, query 31f8f17ce6be853dfd8c92964f250b333d90cba7: [email protected]:53798 from [email protected]:6881. Distance: 116b102ce885d9e05694e610d0f66ca09fd9db52.
[03/25/13 00:37:10] [TRAC] wasContactedRecently for ih=31f8f17ce6be853dfd8c92964f250b333d90cba7 in node [email protected]:53798 returned false
[03/25/13 00:37:10] [TRAC] [email protected]:53798
[03/25/13 00:37:10] [TRAC] newQuery for 6730962b722d07086c265c4f6261c73f3ee2f919, lastID 1
[03/25/13 00:37:10] [TRAC] DHT sending find_node. nodeID: [email protected]:53798, target ID: 31f8f17ce6be853dfd8c92964f250b333d90cba7 , distance: 56c867579493823591aaced92d44cc0c037232be
[03/25/13 00:37:10] [TRAC] wasContactedRecently for ih=31f8f17ce6be853dfd8c92964f250b333d90cba7 in node [email protected]:53798 returned false
[03/25/13 00:37:10] [TRAC] [email protected]:53798
[03/25/13 00:37:10] [TRAC] newQuery for 6730962b722d07086c265c4f6261c73f3ee2f919, lastID 2
[03/25/13 00:37:10] [TRAC] DHT sending find_node. nodeID: [email protected]:53798, target ID: 31f8f17ce6be853dfd8c92964f250b333d90cba7 , distance: 56c867579493823591aaced92d44cc0c037232be
[03/25/13 00:37:10] [TRAC] wasContactedRecently for ih=31f8f17ce6be853dfd8c92964f250b333d90cba7 in node [email protected]:53798 returned false
[03/25/13 00:37:10] [TRAC] [email protected]:53798
[03/25/13 00:37:10] [TRAC] newQuery for 6730962b722d07086c265c4f6261c73f3ee2f919, lastID 3
[03/25/13 00:37:10] [TRAC] DHT sending find_node. nodeID: [email protected]:53798, target ID: 31f8f17ce6be853dfd8c92964f250b333d90cba7 , distance: 56c867579493823591aaced92d44cc0c037232be
[03/25/13 00:37:10] [TRAC] wasContactedRecently for ih=31f8f17ce6be853dfd8c92964f250b333d90cba7 in node [email protected]:53798 returned false
[03/25/13 00:37:10] [TRAC] [email protected]:53798
[03/25/13 00:37:10] [TRAC] newQuery for 6730962b722d07086c265c4f6261c73f3ee2f919, lastID 4
[03/25/13 00:37:10] [TRAC] DHT sending find_node. nodeID: [email protected]:53798, target ID: 31f8f17ce6be853dfd8c92964f250b333d90cba7 , distance: 56c867579493823591aaced92d44cc0c037232be
[03/25/13 00:37:10] [TRAC] wasContactedRecently for ih=31f8f17ce6be853dfd8c92964f250b333d90cba7 in node [email protected]:53798 returned false
[03/25/13 00:37:10] [TRAC] [email protected]:53798
[03/25/13 00:37:10] [TRAC] newQuery for 6730962b722d07086c265c4f6261c73f3ee2f919, lastID 5
[03/25/13 00:37:10] [TRAC] DHT sending find_node. nodeID: [email protected]:53798, target ID: 31f8f17ce6be853dfd8c92964f250b333d90cba7 , distance: 56c867579493823591aaced92d44cc0c037232be

replace jackpal/bencode-go with IncSW/go-bencode

jackpal/bencode-go currently uses a lot of ressources..

Is it maybe easy to use IncSW/go-bencode instead?

I've tried for a while but couldn't get it into the right format/syntax, to get it to work.

Performance

Marshal

Library Time Bytes Allocated Objects Allocated
IncSW/go-bencode 1493 ns/op 554 B/op 15 allocs/op
jackpal/bencode-go 8497 ns/op 2289 B/op 66 allocs/op

Unmarshal

Library Time Bytes Allocated Objects Allocated
IncSW/go-bencode 3151 ns/op 1360 B/op 46 allocs/op
jackpal/bencode-go 6850 ns/op 3073 B/op 102 allocs/op

nil pointer dereference in peer_store.go

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x4 pc=0x41059d]

goroutine 28 [running]:
github.com/nictuku/dht.(_peerContactsSet).put(0xc20030b230, 0xc2010e7dc0, 0x6, 0xc20030b230)
/home/nictuku/src/github.com/nictuku/dht/peer_store.go:42 +0xaf
github.com/nictuku/dht.(_peerStore).addContact(0xc2002e59b0, 0xc201309b20, 0x14, 0xc2010e7dc0, 0x6, ...)
/home/nictuku/src/github.com/nictuku/dht/peer_store.go:121 +0xa6
github.com/nictuku/dht.(_DHT).replyAnnouncePeer(0xc2000f6380, 0xc20173a7b0, 0xc20117cf50, 0x8, 0xc2010e7cd0, ...)
/home/nictuku/src/github.com/nictuku/dht/dht.go:484 +0x2cf
github.com/nictuku/dht.(_DHT).processPacket(0xc2000f6380, 0xc2008f0000, 0x86, 0x1000, 0xc20173a7b0, ...)
/home/nictuku/src/github.com/nictuku/dht/dht.go:389 +0x12b7
github.com/nictuku/dht.(*DHT).DoDHT(0xc2000f6380)
/home/nictuku/src/github.com/nictuku/dht/dht.go:253 +0xa91

example doesn't work as expected, infohash not found, even among neighbors.

I wanted to test a very simple IPv4 DHT. I took 2 ubuntu 14.04 boxes with go-1.3.1 and said go get github.com/nictuku/dht. Lets call them left (192.168.1.2), and right (192.168.1.3). I hard coded both to port 8444. On left/192.168.1.2:
Port: 8444, // 0 Picks a random port.
DHTRouters: "192.168.1.3:8444",

On right/192.168.1.3:
Port: 8444, // Picks a random port.
DHTRouters: "192.168.1.2:8444",

If passed in the same infohash I expected them to find each other, and then accept each other as peers. I ran both copies with:
$ go run main.go -log_dir="log" -v=6 12b9b08b325e877d08cc63a75e8fd24699c3dc6b

In the log left did ok:
I1008 01:46:31.709372 29590 dht.go:233] DHT: torrent client asking more peers for 12b9b08b325e877d08cc63a75e8fd24699c3dc6b.
I1008 01:46:31.709727 29590 dht.go:572] DHT: ping => {IP:192.168.1.3 Port:8444 Zone:}
I1008 01:46:31.709739 29590 krpc.go:92] newQuery for , lastID 1
I1008 01:46:31.709743 29590 krpc.go:95] ... new id 2
I1008 01:46:31.709798 29590 dht.go:326] DHT: Starting DHT node 4fc01e6d67478cb3b959b50c66b87b6ee11a9dbd on port 8444.
I1008 01:46:31.710378 29590 dht.go:445] DHT processing packet from 192.168.1.3:8444
I1008 01:46:31.710404 29590 dht.go:465] DHT processing response from 7e6738648a6d2153d779c4b52924c407b3c6bf87
I1008 01:46:31.710413 29590 dht.go:495] DHT: Received reply to ping
I1008 01:46:31.710419 29590 routing_table.go:276] New neighbor added to neighborhood with proximity 2

Right took longer but:
I1008 01:46:25.598368 23507 dht.go:188] Using a new random node ID: 7e6738648a6d2153d779c4b52924c407b3c6bf87 20
I1008 01:46:25.599059 23507 dht.go:233] DHT: torrent client asking more peers for 12b9b08b325e877d08cc63a75e8fd24699c3dc6b.
I1008 01:46:25.599278 23507 dht.go:572] DHT: ping => {IP:192.168.1.2 Port:8444 Zone:}
I1008 01:46:25.599320 23507 krpc.go:92] newQuery for , lastID 1
I1008 01:46:25.599330 23507 krpc.go:95] ... new id 2
I1008 01:46:25.599408 23507 dht.go:326] DHT: Starting DHT node 7e6738648a6d2153d779c4b52924c407b3c6bf87 on port 8444.
...
I1008 02:01:25.647747 23507 dht.go:445] DHT processing packet from 192.168.1.2:8444
I1008 02:01:25.647780 23507 dht.go:465] DHT processing response from 4fc01e6d67478cb3b959b50c66b87b6ee11a9dbd
I1008 02:01:25.647798 23507 dht.go:495] DHT: Received reply to ping
I1008 02:01:25.647809 23507 routing_table.go:276] New neighbor added to neighborhood with proximity 2
I1008 02:01:25.647818 23507 routing.go:223] wasContactedRecently for ih=7e6738648a6d2153d779c4b52924c407b3c6bf87 in node 4fc01e6d67478cb3b959b50c66b87b6ee11a9dbd@{192.168.1.2 8444 } returned false

So there's connectivity (and no firewalls involved) between left and right, they are exchanging UDP packets, and they have accepted each other as neighbors.

However they never accept each other as peers for the same infohash. So no match on stdout, and while totalNodes and totalNodesReached sits at 1, totalPeers stays at zero.

Is this too simple of a DHT (just 2 nodes)? Am I misunderstanding something?

getpeers broken

My understanding of get_peers is that you look in your routing table for the host closest to the info_hash desired and send out the queries. Said host returns either A) peers for that infohash or B) peers closer to the infohash. Each time we get closer peers the difference between them and the infohash should be less.

So I start a DHT and let it settle:
[11/17/12 10:26:33] [INFO] DHT: Starting DHT node d5d4ff2c3c14850625af007a0ab8b79feac1863a.
Normal establishing of the DHT, totalNodes=400, reachablenodes=129.

Then we do a get Peers:
[11/17/12 10:38:10] [INFO] querying for infoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a
[11/17/12 10:38:10] [WARN] DHT: torrent client asking more peers for 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a. Calling getPeers()

So we should be looking for hosts with a NodeID close to 2015...
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 251695e4558ae09beaad8dfdcd616f132a0e8d66 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 05037e3fdfe49e06cafb9e9cf3dc94fa896e262c
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 2a5a613ed83277f674f47de80d076b5291b4e22d , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 0a4f8ae5525c096b54a26e8933ba90bb32d44967
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 016fa3c0b2ac375a152a0c32cb946e712488d2c5 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 217a481b38c249c7357c1f53f529959887e8798f
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 060e0faa2f13c486ef191896dd326b09818f982f , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 261be471a57dba1bcf4f0bf7e38f90e022ef3365
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 091c00b6886c41c9906d464eefdad831795b7ec6 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 2909eb6d02023f54b03b552fd16723d8da3bd58c
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 127f5e05a4be28d0378829abf63c717047aa43bf , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 326ab5de2ed0564d17de3acac8818a99e4cae8f5
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 1788fda3fe4b66e7bdff4d0eb1b8024c6fe89912 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 379d16787425187a9da95e6f8f05f9a5cc883258
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 18b3a9a4a34b5d9eda83200a3abbe706b3b3bb42 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 38a6427f29252303fad5336b04061cef10d31008

There is a host "251695e4558ae09beaad8dfdcd616f132a0e8d66" which is pretty close, only "05037e3fdfe49e06cafb9e9cf3dc94fa896e262c" away.

But it fails to converge:
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 21e11cea491b0323df20386e56975ff18f59c94b , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 01f4f731c3757dbeff762b0f682aa4182c396201
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 481938abb30a841d86af884c5e71173f2943661f , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 680cd3703964fa80a6f99b2d60ccecd68a23cd55
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 4805fe36160cd91b48132b2f2f3a67aa70a0fec8 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 681015ed9c62a7866845384e11879c43d3c05582
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 4807fb3c65b1370471cf8fdcceb6931c6d0f798d , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 681210e7efdf499951999cbdf00b68f5ce6fd2c7
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 48348291edf47e3483f27b8ebcb04e36a68d23b4 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6821694a679a00a9a3a468ef820db5df05ed88fe
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 48340685e2ea8ffba7418fcf0cd6a58c89570ef8 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6821ed5e6884f16687179cae326b5e652a37a5b2
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 483667cc5cfb711617aad876f27a95c3ec562c97 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 68238c17d6950f8b37fccb17ccc76e2a4f3687dd
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 48365ef72d4d339eb95c194a9582df9aaeaa87ca , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6823b52ca7234d03990a0a2bab3f24730dca2c80

Still not converging:

[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 3b7f8394e54265b33f84749ee3be255a98f98f4e , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 1b6a684f6f2c1b2e1fd267ffdd03deb33b992404
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487da26e4f402728c39954ff74e12509fdc71f9e , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 686849b5c52e59b5e3cf479e4a5cdee05ea7b4d4
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d844f83e86adf326e3ae29d8a2b04edb3fd50 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 68686f940986144212382983a337d0ed4ed3561a
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d99965802183012cfd3d7bec3f88b556139b2 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6868724dd26c66ad3299c0b6807e0362f60192f8
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d96828f24e435db79c5b0830e66ef36d7aece , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 68687d59054a9aa8fb2fd6d1bdb39d0695b70584
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d7f0585c202cd7844a993351941bf197a34e0 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 686894de0fac7c505812baf20ba4ba56ba1a9faa
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d539474f9fd2d98e0762999e51d36f05d9c90 , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6868b84ffe9783b0b8b66548a758e6df533d37da
[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: 487d206f9b133ddc225d1d571f4e0547892e376d , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a , distance: 6868cbb4117d4341020b0e3621f3feae2a4e9c27

Over 3000 get_peers are sent.

Including some pretty ridiculously far peers from 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a:

[11/17/12 10:38:10] [TRAC] DHT sending get_peers. nodeID: fe9408d54927f07bf9d458ebb717d45f6c180c2f , InfoHash: 2015ebdb8a6e7e9d205613613ebdfbe9a360ab4a

The pseudo code should be more like:

  1. setup 8 host buckets for each hosts based on distance. Each bucket is for hosts more distant than a factor of 2
  2. Find the bucket closest to the infoHash
  3. send all peers in bucket a get_peers
    loop till info hash is found or distance stops decreasing:
    4) parse results for A) peers of the infohash or B) peers closer to the info hash
    5) send the best N (around 8) peers a get_peers

That does not seem to be what is happening. Distance between NodeID and Infohash should steadily decrease. Each iteration of the loop should get you a factor of 2 closer to your goal.

Fix test data races

I believe there are only two races: one in the call to ping(), another in the call to reachableNodes().

WARNING: DATA RACE
Read by goroutine 9:
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).hostPortToNode()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:52 +0x218
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).getOrCreateNode()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:121 +0x75
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).ping()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:404 +0x85
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).DoDHT()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:200 +0x1c6

Previous write by goroutine 5:
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).insert()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:108 +0x16c
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).getOrCreateNode()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:144 +0x40f
_/Users/yves/go/src/github.com/nictuku/dht.(*DHT).ping()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:404 +0x85
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:81 +0x1097
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Goroutine 9 (running) created at:
_/Users/yves/go/src/github.com/nictuku/dht.startDHTNode()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:64 +0x150
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:71 +0x43
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Goroutine 5 (running) created at:
testing.RunTests()
/Users/yves/go/src/pkg/testing/testing.go:377 +0xaec
testing.Main()
/Users/yves/go/src/pkg/testing/testing.go:313 +0xcd
main.main()
_/Users/yves/go/src/github.com/nictuku/dht/_test/_testmain.go:61 +0xda
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

WARNING: DATA RACE
Read by goroutine 5:
_/Users/yves/go/src/github.com/nictuku/dht.(*routingTable).reachableNodes()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:67 +0x21a
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:87 +0x2db
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Previous write by goroutine 9:
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).getOrCreateNode()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:142 +0x24c
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).ping()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:404 +0x85
_/Users/yves/go/src/github.com/nictuku/dht.(*DHT).DoDHT()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:200 +0x1c6

Goroutine 5 (running) created at:
testing.RunTests()
/Users/yves/go/src/pkg/testing/testing.go:377 +0xaec
testing.Main()
/Users/yves/go/src/pkg/testing/testing.go:313 +0xcd
main.main()
_/Users/yves/go/src/github.com/nictuku/dht/_test/_testmain.go:61 +0xda
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

Goroutine 9 (running) created at:
_/Users/yves/go/src/github.com/nictuku/dht.startDHTNode()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:64 +0x150
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:71 +0x43
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

WARNING: DATA RACE
Read by goroutine 5:
_/Users/yves/go/src/github.com/nictuku/dht.(*routingTable).reachableNodes()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:67 +0x21a
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:87 +0x2db
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Previous write by goroutine 9:

Goroutine 5 (running) created at:
testing.RunTests()
/Users/yves/go/src/pkg/testing/testing.go:377 +0xaec
testing.Main()
/Users/yves/go/src/pkg/testing/testing.go:313 +0xcd
main.main()
_/Users/yves/go/src/github.com/nictuku/dht/_test/_testmain.go:61 +0xda
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

Goroutine 9 (running) created at:
_/Users/yves/go/src/github.com/nictuku/dht.startDHTNode()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:64 +0x150
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:71 +0x43
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

WARNING: DATA RACE
Read by goroutine 5:
_/Users/yves/go/src/github.com/nictuku/dht.(*routingTable).reachableNodes()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:68 +0x244
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:87 +0x2db
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Previous write by goroutine 9:

Goroutine 5 (running) created at:
testing.RunTests()
/Users/yves/go/src/pkg/testing/testing.go:377 +0xaec
testing.Main()
/Users/yves/go/src/pkg/testing/testing.go:313 +0xcd
main.main()
_/Users/yves/go/src/github.com/nictuku/dht/_test/_testmain.go:61 +0xda
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

Goroutine 9 (running) created at:
_/Users/yves/go/src/github.com/nictuku/dht.startDHTNode()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:64 +0x150
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:71 +0x43
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

WARNING: DATA RACE
Read by goroutine 5:
_/Users/yves/go/src/github.com/nictuku/dht.(*routingTable).reachableNodes()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:67 +0x21a
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:87 +0x2db
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

Previous write by goroutine 9:
_/Users/yves/go/src/github.com/nictuku/dht.(_routingTable).getOrCreateNode()
/Users/yves/go/src/github.com/nictuku/dht/routing_table.go:142 +0x24c
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).processFindNodeResults()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:672 +0x54a
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).processPacket()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:363 +0xad1
_/Users/yves/go/src/github.com/nictuku/dht.(_DHT).DoDHT()
/Users/yves/go/src/github.com/nictuku/dht/dht.go:244 +0x84b

Goroutine 5 (running) created at:
testing.RunTests()
/Users/yves/go/src/pkg/testing/testing.go:377 +0xaec
testing.Main()
/Users/yves/go/src/pkg/testing/testing.go:313 +0xcd
main.main()
_/Users/yves/go/src/github.com/nictuku/dht/_test/_testmain.go:61 +0xda
runtime.main()
/Users/yves/go/src/pkg/runtime/proc.c:248 +0x91

Goroutine 9 (running) created at:
_/Users/yves/go/src/github.com/nictuku/dht.startDHTNode()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:64 +0x150
_/Users/yves/go/src/github.com/nictuku/dht.TestDHTLarge()
/Users/yves/go/src/github.com/nictuku/dht/dht_test.go:71 +0x43
testing.tRunner()
/Users/yves/go/src/pkg/testing/testing.go:301 +0xe8

panic in replyAnnouncePeer

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x53c3eb]

goroutine 26 [running]:
runtime.panic(0x74dfe0, 0x9708b3)
        /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/nictuku/dht.(*DHT).replyAnnouncePeer(0xc208003560, 0x0, 0xc208107d88, 0x4, 0xc208107e8a, 0x1, 0xc208107d50, 0xd, 0x0, 0x0, ...)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:659 +0x59b
github.com/nictuku/dht.(*DHT).processPacket(0xc208003560, 0xc2080b0000, 0xea, 0x1000, 0xc20811b408, 0x4, 0x4, 0xceba, 0x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:553 +0x1843
github.com/nictuku/dht.(*DHT).Run(0xc208003560, 0x0, 0x0)
        /home/nictuku/src/github.com/nictuku/dht/dht.go:385 +0xca4
created by github.com/jackpal/Taipei-Torrent/torrent.NewTorrentSession
        /home/nictuku/src/github.com/jackpal/Taipei-Torrent/torrent/torrent.go:172 +0x510

goroutine 16 [select]:
github.com/jackpal/Taipei-Torrent/torrent.RunTorrents(0xc208042680, 0xc2080040b0, 0x1, 0x1, 0x0, 0x0)
        /home/nictuku/src/github.com/jackpal/Taipei-Torrent/torrent/torrentLoop.go:67 +0xea7
main.main()
        /home/nictuku/src/github.com/jackpal/Taipei-Torrent/main.go:111 +0x737

support the dht store extension

Summary of the changes so far:

  • I can use libtorrent's code to query DHT nodes and get/put items.
  • I haven't written test cases or cleaned up the code.
  • It needs a lot of work.

I have a tarball of some partially working code here. It's the repository + my files. It really is a work in progress -- nowhere near ready for integration right now. Some of the code is likely incorrect; I explain why below.

I've tested libtorrent against my code, and using libtorrent's standalone dht_put program, I can both put and get immutable data from my modified DHT code. Here's what I did:

I started dht/examples/router on a server that's reachable from the internet. It's a small program that starts a DHT on port 9882, does not announce itself with the public routers, and waits forever for connections. I started the router with ./router -v=5 -logtostederr=true so I could see all the activity.
I downloaded and unpacked libtorrent-rasterbar-1.0.1, and added dht_put.cpp to the tools directory. I modified the file to make it use only my router node. To compile it, you can either modify tools/Makefile.am to add a build target for dht_put (you'll need automake 1.14 installed) or compile it manually.

After compiling dht_put, type ./dht_put put "hello there". It should talk to the router, and do a get followed by a put (you'll see that in the router's output). It'll print out the SHA-1 hash for the string 11:hello there, and you'll see the router store the value hello there. Next, if you try ./dht_put get <the hash>, it should talk to the router and return the string hello there. If you give it a different hash, it won't be able to fetch anything.

One thing that I didn't pay attention to carefully is the argument for put as described in the spec. You have to give it a valid object that can be bencoded -- a string, an integer, a list, or a dictionary. The code on both sides (the sending node and the storage node) will bencode the object before calculating the SHA-1 hash.

I'm sort of aiming for the same public UI for the DHT Get and Put methods: GET takes an infohash, and PUT takes a bencodable object (maybe as a string?).

One thing I haven't had much success with is using the DHT's methods to actually get/put stuff. I wrote a small amount of code (not in the tarball) to operate the same way as dht_put, but it seems to spin after it receives the string to be sent out over the network, somewhere in the put method in getput.go.

A problem I have is that I haven't looked at the client code (Taipei) yet, so I don't have a good idea on how to integrate things properly. I mean to work on this today (Thursday), but stuff came up at home, and I've been busy.

No way to remove info hash from peer store

I am using the library in a torrent client. When a torrent is removed from the client, I would also like to remove the info hash from DHT node. Currently, there isn't any method for this. I can add one if you are okay with it. Would you like to see a PR?

byteArena question - possible bug?

// Read from UDP socket, writes slice of byte into channel.
func readFromSocket(socket *net.UDPConn, conChan chan packetType, bytesArena arena, stop chan bool, log DebugLogger) {
	for {
		b := bytesArena.Pop()
		n, addr, err := socket.ReadFromUDP(b)
		if err != nil {
			log.Debugf("DHT: readResponse error:%s\n", err)
		}
		b = b[0:n]
		if n == maxUDPPacketSize {
			log.Debugf("DHT: Warning. Received packet with len >= %d, some data may have been discarded.\n", maxUDPPacketSize)
		}
		totalReadBytes.Add(int64(n))
		if n > 0 && err == nil {
			p := packetType{b, *addr}
			select {
			case conChan <- p:
				continue
			case <-stop:
				return
			}
		}
		// Do a non-blocking read of the stop channel and stop this goroutine if the channel
		// has been closed.
		select {
		case <-stop:
			return
		default:
		}
	}
}

If I get that right you do a bytesArena.Pop() to get a pre-allocated buffer. but in case of a 0 byte package or an error you never return that buffer back, since that happens only for packets in conChan aka socketChan (dht.go:499).

my dht client recently began to randomly stopping to receiving/process any incoming packets until I restart.. so I began digging.. and that might be the reason?

Pass port argument to PeersRequest method

I have a torrent client that serves each torrent on a seperate TCP port. I need to specify port in announce_peer query. Current PeersRequest method does not take any port argument and always use Config.Port. @nictuku can I add another method like:

func (d *DHT) PeersRequestPort(ih string, announce bool, port int)

Proposal/Feature request: AddToBlackList

Annoyingly many peers will claim they are peers for any requested infohash. Some way to black list them would be useful. Two potential strategies:

  1. pick a random infohash, statistically the chance of a collision in 2^160 is low,
    put anyone that replies on black list.
  2. For an infohash you want for any peer that responds ask that peer for the infohash+1. If they also claim to be a peer for that infohash+1 they are lying.

go test ends strangely.

This should run TestDHTLarge, I updated to the current version just minuts ago?
$ go test

It seems to not complete and expire with a timer. The output should end with:
=== Stats ===
totalReachableNodes:
totalDupes:
totalPeers:
totalSentGetPeers:

Or maybe I misunderstand. Maybe I need to adjust the timers? I'm on a fast machine with a fairly fast network connection (10mbit) without any firewall. I see a fair bit of output, but it doesn't seem to exist normally:

[11/09/12 10:01:41] [TRAC] DHT: Got new node reference: [email protected]:49001 from [email protected]:49001. Distance: d749f235cdd12aa4a3cda5625c8d3887285fbd49.
[11/09/12 10:01:41] [TRAC] DHT sending get_peers. nodeID: aa9d7b2d164d65ea74588378ab7d898d93dfbbeb , InfoHash: b462c0a8bcef1ce5bb56b9fdb8cf37ffd02f5f59 , distance: 1effbb85aaa2790fcf0e3a8513b2be7243f0e4b2
[11/09/12 10:01:41] [TRAC] DHT: Got new node reference: [email protected]:27977 from [email protected]:49001. Distance: d749f235cdd12aa4a3cda5625c8d3887285fbd49.
[11/09/12 10:01:41] [TRAC] DHT sending get_peers. nodeID: d78756c13f577d504599054ee1ee218a2b37d88d , InfoHash: b462c0a8bcef1ce5bb56b9fdb8cf37ffd02f5f59 , distance: 63e5966983b861b5fecfbcb359211675fb1887d4
[11/09/12 10:01:46] [WARN] DHT: torrent client asking more peers for d1c5676ae7ac98e8b19f63565905105e3c4c37a2. Calling getPeers().
PASS
ok _/home/bill/tmp/git/dht 9.062s
$

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.