A whispernet written in Go. Continued from Google's excellent code lab: https://code.google.com/p/whispering-gophers/
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Whispering Gophers

A whispernet written in Go.

Based on: https://code.google.com/p/whispering-gophers/

Getting Started

If you have not worked in GO before (i.e., don't have a GOPATH), then start here:

mkdir ~/somedir
cd somedir
export GOPATH=~/somedir
git clone https://github.com/pdxgo/whispering-gophers.git
go get github.com/pdxgo/whispering-gophers
cd whispering-gophers
go build


For the first peer:

go run main.go -nick phil

Next peers:

go run main.go -peer $IP_OF_PEER:55555 -nick goldy

Where $IP_OF_PEER is the IP address printed by a running peer.


Peers are long running programs which accept user input and display messages from other peers. At the minimum a well participating peer must:

  • Manually connect to at least 1 peer
  • Bind to an address and accept connections from any peer

Messages should be of the form:

    "ID": "<globally unique string>",
    "Addr": "<IP:Port the sender is listening on>",
    "Body": "<the actual message to display>"

Peers should follow the following behavior with regard to messages:

  • Display messages (Body key) from other peers
  • Disconnect peers which send malformed messages
  • Accept user input as Body content
  • Send messages to all known peers.
  • When sending messages Addr must be the IP:Port combination the peer is listening on.
  • Connect to new peers seen in Addr fields of received messages
  • Broadcast all messages to all peers (except Addr); store list of Seen messages by ID to avoid rebroadcasting
  • Payloads without a Body and/or with unknown keys should be silently ignored to support extensions
  • Messages are not delimited or framed. Multiple messages may be sent across a single connection. Peers recieving messages must detect the end of the JSON object to know when one message ends and another may begin.

Connections are unidirectional. In a healthy whispernet each peer will have 1 outgoing connection to send messages to every other peer, as well as 1 incoming connection from each peer for receiving messages.


Roughly ordered based on difficulty.

  1. Pretty display messages Done!
  2. Nicks! Done!
  3. Forget old message IDs (the basic daemon slowly uses all memory) - may use Timestamp field - see below
  4. Base ID on hash of Addr + Body + Timestamp - see below
  5. Discover based on UDP broadcasts See below - Partially done
  6. Build web interface into daemon
    1. Simple input form (textbox + submit button)
    2. Chat output (refreshed on a timer or using websockets if you're really fancy)
    3. Peer connection controls (connect to a new host, disconnect from a host)
  7. File transfers - see below
  8. Send backlog to newly connected peers - see backlog below
  9. Flood control: Disconnect and blacklist peers whose activity exceeds a threshold
  10. PKI all the things
  11. Scalable routing

UDP Broadcast Protocol

Broadcasts should be of the form: "IP:PORT" (same as Addr) and may be sent on behalf of any peers.

Timestamp field

To support various features, messages should include an optional Timestamp field of the format milliseconds since UNIX epoch as a number. For example:

    "ID": "abc123",
    "Addr": "",
    "Body": "Hello world!",
    "Timestamp": 1382050782085

Hashed ID field

To support very rudimentary payload verification, use a hash of the concatenated Addr, Body, and Timestamp fields. To allow backward compatibility with old clients, hashed IDs should be of the form:

    "ID": "hash:sha256:<hash>",

Where each string starts with "hash:" followed by the name of the hash function used, followed by a colon and the hex encoded hash.

Unknown hash functions should cause the reader to revert to the basic random-string-ID behavior.

Peers should drop messages whose hashes don't match the current message payload.

File transfers

Two new keys: "FileType" and "FileContents"

  • FileType should be the MIME type like: "image/gif"
  • FileContents should be the Base64 encoded file contents


Upon receiving a new connection from a peer, a daemon should replay that peer the last N messages (the actual number shouldn't be important) to the peer.