Pure-Go library for cross-platform local peer discovery using UDP multicast :woman: :repeat: :woman:

Overview

peerdiscovery

Code coverage Go Report Go Doc

Pure-go library for cross-platform thread-safe local peer discovery using UDP multicast. I needed to use peer discovery for croc and everything I tried had problems, so I made another one.

Install

Make sure you have Go 1.5+.

go get -u github.com/schollz/peerdiscovery

Usage

The following is a code to find the first peer on the local network and print it out.

discoveries, _ := peerdiscovery.Discover(peerdiscovery.Settings{Limit: 1})
for _, d := range discoveries {
    fmt.Printf("discovered '%s'\n", d.Address)
}

Here's the output when running on two computers. (Run these gifs in sync by hitting Ctl + F5).

Computer 1:

computer 1

Computer 2:

computer 1

For more examples, see the scanning examples (ipv4 and ipv6) or the docs.

Testing

To test the peer discovery with just one host, one can launch multiple containers. The provided Dockerfile will run the example code. Please make sure to enable Docker's IPv6 support if you are using IPv6 for peer discovery.

# Build the container, named peertest
$ docker build -t peertest .

# Execute the following command in multiple terminals
$ docker run -t --rm peertest
Scanning for 10 seconds to find LAN peers
 100% |████████████████████████████████████████|  [9s:0s]Found 1 other computers
0) '172.17.0.2' with payload 'zqrecHipCO'

Contributing

Pull requests are welcome. Feel free to...

  • Revise documentation
  • Add new features
  • Fix bugs
  • Suggest improvements

Thanks

Thanks @geistesk for adding IPv6 support and a Notify func, and helping maintain! Thanks @Kunde21 for providing a bug fix and massively refactoring the code in a much better way. Thanks @robpre for finding and fixing bugs. Thanks @shvydky for adding dynamic payloads.

License

MIT

Issues
  • Ignoring configured address family can lead to deadlock on MacOS

    Ignoring configured address family can lead to deadlock on MacOS

    After getting the list of interfaces, interfaces not having at least one address of the configured address family are not skipped.

    Sending a multicast with an IPv4 connection on an IPv6-only interface results (at least on MacOS) in a deadlock.

    Additionally, you should check the interface flags if is up and if it supports multicast at all.

    This issue might be the root cause of https://github.com/schollz/croc/issues/313

    opened by thewilli 6
  • Discovery hangs if executed in a loop

    Discovery hangs if executed in a loop

    I tried executing peerdiscovery.Discover() function in a loop and it stucks randomly after some time. After a little debugging, my hunch is, this is due to connection not being closed in listen() function. Please let me know if this is the actual reason or it is because of something else.

    needs information 
    opened by jainpiyush19 5
  • can't find each other

    can't find each other

    discoveries, _ := peerdiscovery.Discover(peerdiscovery.Settings{Limit: -1,TimeLimit: -1})
    for _, d := range discoveries {
        fmt.Printf("discovered '%s'\n", d.Address)
    }
    

    run on a, b and c that are independent mac. result: a can discover b and c b can discover c c can't discover a or b

    go 1.14 mac 10.15.3

    opened by xurwxj 4
  • IPv6 support

    IPv6 support

    This pull request adds IPv6 multicast scans by introducing the IPVersion field to the Settings struct, defaulting to IPv4 to not break the compatibility. However, settings IPVersion: IPv6 will execute the same peer discovery service, just for IPv6 instead.

    The code is a bit ugly at some points, because both ipv4.PacketConn and ipv6.PacketConn does not implement net.PacketConn. Therefore I treated them as an empty interface.

    Please tell me what you think and thanks a lot for this library!


    Random note regarding testing: I wrote a small Dockerfile which launches - after enabling IPv6 - some containers for testing.

    $ cat Dockerfile
    FROM golang:1.11
    
    WORKDIR /peerdiscovery
    COPY . .
    RUN go build ./examples/main.go
    
    CMD ["/peerdiscovery/main"]
    
    $ docker build -t peertest .
    . . .
    
    # run the following command in multiple terminals
    $ docker run -t --rm peertest
    
    opened by oxzi 4
  • Fix StopChan behaviour

    Fix StopChan behaviour

    This seems to fix the exit behaviour, since the exit variable was created for the for loop scope, setting it to true at the end of the loop meant it wasn't being caught by the check on line 214.

    I wasn't sure if we should just move the if to under the select, but this seemed like the lowest-impact fix.

    Thanks for this module! :)

    opened by robpre 3
  • Enable unlimit scanning and notify function

    Enable unlimit scanning and notify function

    Enabling unlimitted scanning by setting TimeLimit to a negative value and setting Notify to a function, consuming a Discovered struct, will let the peerdiscovery library run forever. Each discovery, regardless of wether known before or not, will be passed to the Notify function. This implementation is oriented by the observer pattern.

    I needed the described change of the library for my use case. This enables scanning for new peers in the background and letting me decide if I want to establish a connection to those hosts.

    Please give me a feedback, if this is helpful for you or this library at all?

    opened by oxzi 2
  • Close PacketConn listener when StopChan signals exit

    Close PacketConn listener when StopChan signals exit

    One way to address https://github.com/schollz/peerdiscovery/issues/28

    While not perfect it helps for me, where a long running process repeatably start/stops discovering. Else the process will stop at some point with "too many open files".

    opened by fzwoch 1
  • Listen socket keeps opened indefinitely when stopped via StopChan

    Listen socket keeps opened indefinitely when stopped via StopChan

    When using StopChan to stop the discovery the listen() function never returns and therefore keeps the socket opened indefinitely.

    I was able to quickly hack it in a way so that the local exit variable was part of the peerDiscovery type and listen() would check if that variable is set and quits.

    Not sure if that's nice though. Also, in case no more peer discoveries are happening that function would still sit there forever with its socket listening for valid data.

    opened by fzwoch 1
  • Port doesn't get closed upon discovery complete

    Port doesn't get closed upon discovery complete

    I've wrapped the Discover function like this:

    func Discover() {
    	info := make(map[string]string)
    	info["name"] = "device"
    	info["id"] = "1"
    	info["address"] = ip
    
    	b, _ := json.Marshal(&info)
    
    	for {
    		_, err := peerdiscovery.Discover(peerdiscovery.Settings{
    			Limit:   -1,
    			Payload: b,
    			Notify: func(d peerdiscovery.Discovered) {
    				// save the discovered nodes into memory
    			},
    		})
    		if err != nil {
    			log.Errorf("Error trying to discover peers: %s", err)
    		}
    		time.Sleep(5 * time.Second)
    	}
    }
    
    

    If I'm understanding the Settings correctly, this should discover for 10 secs (default) for unlimited nodes, exits, and restart in 5 secs.

    But what I'm seeing here is that after the discovery completes, there's a lot of listeners on port 9999 (default):

    $ sudo lsof -i:9999 -n -P | wc -l
    1041
    

    Is there a way to close these listeners after the function is finished?

    EDIT: The reason I'm running this in a loop is that if I set the time limit to -1, it works for some time; if the network changes, it will just stop discovering/being discovered altogether. So I figured maybe I'll just let it run periodically for 10 secs.

    opened by maddie 1
  • Add possibility to generate payload dynamically

    Add possibility to generate payload dynamically

    In my case, it is required to send different payloads in every broadcast.

    I propose to have an optional function pointer in Settings that will return payload on demand. In case when this pointer is nil the implementation should fallback to Payload field.

    I will try to implement this in the fork and create PR.

    @schollz, please let me know what do you think about my idea?

    opened by shvydky 1
  • Index out of range error in some rare cases

    Index out of range error in some rare cases

    Sometimes panic occurs while discovery in progress:

    panic: runtime error: index out of range [6] with length 6
    
    goroutine 19 [running]:
    github.com/schollz/peerdiscovery.Discover(0xc0002e5e50, 0x1, 0x1, 0xc00048a000, 0x6, 0x6, 0x0, 0x0)
    	c:/projects/go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:228 +0x1194
    
    opened by shvydky 1
  • Reintroduce Loopback Device Support

    Reintroduce Loopback Device Support

    The filterInterfaces function reduces the useable network interfaces for peer discovery. Due to two changes introduced in v1.6.4^0 and v1.6.5^1, a self-discovery over a loopback device was no longer possible.

    For reasons, a device either holds the loopback flag or the multicast flag, not both together. This commit reflects this.

    Furthermore, some refactoring of the filterInterfaces function was performed to ease its understandability.

    opened by oxzi 0
  • use a deadline to check for exit

    use a deadline to check for exit

    A proposal. Use a deadline for the read operation in the Go routine. In case the routine is supposed to shut down but no traffic is happening on the multicast address this routine never gets the chance to quit.

    Instead time out the read operation after 5 seconds of no data and check whether shut down is expected.

    ~~Note that this is done against master branch. In case #29 gets accepted in some form the check for shutdown should be extended here too.~~

    opened by fzwoch 3
  • Doesn't work with AllowSelf on windows

    Doesn't work with AllowSelf on windows

    I've tried the IPV4 example with AllowSelf set to true on windows, without any other changes but It doesn't discover other local peers.

    But it works on my android 10 device android/arm64 cross-compiled on windows run via termux. Windows can't discover the android peer but android can discover another instance of itself and also windows (in the same wifi).

    opened by phanirithvij 0
  • Can't compile using gcc-go

    Can't compile using gcc-go

    I've tested 2 gcc-go versions on Arch Linux 10.2.0 and 10.3.0 go version go1.14.4 gccgo (GCC) 10.2.0 linux/amd64 go version go1.14.6 gccgo (GCC) 10.3.0 linux/amd64

    I've also tested on Debian testing, just to see if it was maybe Arch issue, but got same error gccgo-go on Debian testing reports go version go1.14.6 gccgo (Debian 10.2.1-6) 10.2.1 20210110 linux/amd64 the error is

    go get -u github.com/schollz/peerdiscovery
    # github.com/schollz/peerdiscovery
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
      381 | type PacketConn4 struct {
          |      ^
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type ipv4.genericOpt)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:381:6: error: incompatible type for receiver (cannot use type PacketConn4 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
      396 | type PacketConn6 struct {
          |      ^
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type ipv6.genericOpt)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    ../../go/src/github.com/schollz/peerdiscovery/peerdiscovery.go:396:6: error: incompatible type for receiver (cannot use type PacketConn6 as type socket.Conn)
    

    tagging https://github.com/schollz/croc/issues/360

    opened by micwoj92 1
  • DisableBroadcast property could be dynamic

    DisableBroadcast property could be dynamic

    Hi, We started using the framework to quickly span multiple nodes for some MPC tests, and we really really like it. It allows us to mostly forget about the network setup. Great work! What would be nice is a little of dynamic management, especially Broadcast and Interval. Or, alternatively, a slightly better restart capability (some go routines like listen() are tricky ). Would you accept such a PR for a review? Cheers!

    opened by kubasiemion 1
  • cant discover others when wake from hibernate

    cant discover others when wake from hibernate

    how to fix it? cant discover others when a win10 host waked from hibernate, others can discover it. if reboot or switch the lan of win10, then all gone well.

    go 1.14 mac 10.15.3 win10 professional

    opened by xurwxj 2
Releases(v1.6.11)
Owner
Zack
Tinkerer
Zack
Zero Trust Network Communication Sentinel provides peer-to-peer, multi-protocol, automatic networking, cross-CDN and other features for network communication.

Thank you for your interest in ZASentinel ZASentinel helps organizations improve information security by providing a better and simpler way to protect

ZTALAB 6 Jul 30, 2022
An imageboard, but images are stored in a peer-to-peer network

Interplanetary File Dumpster An imageboard, but images are stored in a peer-to-peer network Features: Easy file sharing without registration and SMS.

George 93 Jun 25, 2022
DeepValueNetwork is a peer-to-peer database network managed and hosted by its community.

DeepValueNetwork To understand what DeepValueNetwork will be, I suggest you read this document. In progress This software is currently being developed

DeepValue Network 337 Jul 26, 2022
📦 Command line peer-to-peer data transfer tool based on libp2p.

pcp - Peer Copy Command line peer-to-peer data transfer tool based on libp2p. Table of Contents Motivation Project Status How does it work? Usage Inst

Dennis Trautwein 877 Jul 27, 2022
Group peer to peer video calls for everyone written in Go and TypeScript

Peer Calls v4 WebRTC peer to peer calls for everyone. See it live in action at peercalls.com. The server has been completely rewriten in Go and all th

Peer Calls 1.1k Aug 6, 2022
Peer-to-peer hypermedia protocol

IPFS powers the Distributed Web A peer-to-peer hypermedia protocol to make the web faster, safer, and more open. TL;DR Get help and talk about ideas i

IPFS 21k Aug 1, 2022
Steve - A peer-to-peer (p2p) decentralized network

Steve Steve is a peer-to-peer (p2p) decentralized network that enables people to

Steve Care Software Inc 4 Feb 5, 2022
UDP Transport: compress, encrypt and send any data reliably over unreliable UDP connections

udpt UDP Transport Compresses, encrypts and transfers data between a sender and receiver using UDP protocol. Features and Design Aims: Avoid the overh

Ali Bala 41 Jul 30, 2022
UDP output for beats to send events over UDP.

beats-udp-output How To Use Clone this project to elastic/beats/libbeat/output/ Modify elastic/beats/libbeat/publisher/includes/includes.go : // add i

ichx 0 Dec 11, 2021
Cross platform local network clipboard sync.

clipSync Synchronize clipboard content across multiple devices. Features Rapidly synchronize clipboard content to all devices in same local network. S

Rick Mark 3 Jan 3, 2022
A toy MMO example built using Ebiten and WebRTC DataChannels (UDP)

Ebiten WebRTC Toy MMO ⚠️ This is a piece of incomplete hobby work and not robust. Please read the "Why does this project exist?" section. What is this

Jae Bentvelzen 14 Jul 31, 2022
P2P Forwarder - a tool for farwarding tcp/udp ports. Made using libp2p.

P2P Forwarder A tool for farwarding ports. Made using libp2p. How it works A: opens desired ports ports inside P2P Forwarder A: shares it's id from P2

null 23 Jan 14, 2022
Cross-platform, multi-server chat app built using Fyne

Fibro Really early days proof of concept for a cross-platform multi-server chat. Feel free to play, but don't expect it to do much! Features Multiple

Andy Williams 21 Jun 16, 2022
Cross-poster - A cross-posting tool for golang

How to start cp config.example.json config.json update config in config.json Bui

Sagleft 0 Feb 19, 2022
Subfinder is a subdomain discovery tool that discovers valid subdomains for websites by using passive online sources

Subfinder is a subdomain discovery tool that discovers valid subdomains for websites. Designed as a passive framework to be useful for bug bounties and safe for penetration testing.

ProjectDiscovery 5.9k Aug 2, 2022
A Crypto-Secure, Production-Grade Reliable-UDP Library for golang with FEC

Introduction kcp-go is a Production-Grade Reliable-UDP library for golang. This library intents to provide a smooth, resilient, ordered, error-checked

xtaci 3.4k Aug 1, 2022
SOCKS Protocol Version 5 Library in Go. Full TCP/UDP and IPv4/IPv6 support

socks5 中文 SOCKS Protocol Version 5 Library. Full TCP/UDP and IPv4/IPv6 support. Goals: KISS, less is more, small API, code is like the original protoc

TxThinking 476 Jul 30, 2022
Reliable, thin UDP library for Golang targetting games.

⚠️ Do not use this. There's a lot to be worked on here and it's still not comple

sailormoon 2 Dec 27, 2021