main.go 4.67 KB
Newer Older
Jeromy's avatar
Jeromy committed
1
2
3
package main

import (
Hector Sanjuan's avatar
Hector Sanjuan committed
4
	"bufio"
5
	"context"
6
	"crypto/rand"
Jeromy's avatar
Jeromy committed
7
8
	"flag"
	"fmt"
9
	"io"
Jeromy's avatar
Jeromy committed
10
11
	"io/ioutil"
	"log"
12
	mrand "math/rand"
Jeromy's avatar
Jeromy committed
13

Hector Sanjuan's avatar
Hector Sanjuan committed
14
	golog "github.com/ipfs/go-log"
Jeromy's avatar
Jeromy committed
15
	libp2p "github.com/libp2p/go-libp2p"
Hector Sanjuan's avatar
Hector Sanjuan committed
16
	crypto "github.com/libp2p/go-libp2p-crypto"
Jeromy's avatar
Jeromy committed
17
	host "github.com/libp2p/go-libp2p-host"
Jeromy's avatar
Jeromy committed
18
	net "github.com/libp2p/go-libp2p-net"
Jeromy's avatar
Jeromy committed
19
20
21
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
Hector Sanjuan's avatar
Hector Sanjuan committed
22
	gologging "github.com/whyrusleeping/go-logging"
Jeromy's avatar
Jeromy committed
23
24
)

Hector Sanjuan's avatar
Hector Sanjuan committed
25
26
// makeBasicHost creates a LibP2P host with a random peer ID listening on the
// given multiaddress. It will use secio if secio is true.
27
28
29
30
31
32
33
34
35
36
37
38
func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error) {

	// If the seed is zero, use real cryptographic randomness. Otherwise, use a
	// deterministic randomness source to make generated keys stay the same
	// across multiple runs
	var r io.Reader
	if randseed == 0 {
		r = rand.Reader
	} else {
		r = mrand.New(mrand.NewSource(randseed))
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
39
40
	// Generate a key pair for this host. We will use it at least
	// to obtain a valid host ID.
Jeromy's avatar
Jeromy committed
41
	priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
Hector Sanjuan's avatar
Hector Sanjuan committed
42
43
44
45
	if err != nil {
		return nil, err
	}

Jeromy's avatar
Jeromy committed
46
47
48
	opts := []libp2p.Option{
		libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", listenPort)),
		libp2p.WithPeerKey(priv),
Jeromy's avatar
Jeromy committed
49
50
	}

Jeromy's avatar
Jeromy committed
51
52
	if !secio {
		opts = append(opts, libp2p.NoSecio)
Jeromy's avatar
Jeromy committed
53
54
	}

Jeromy's avatar
Jeromy committed
55
	basicHost, err := libp2p.New(context.Background(), opts...)
56
57
58
59
	if err != nil {
		return nil, err
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
60
61
62
63
64
	// Build host multiaddress
	hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", basicHost.ID().Pretty()))

	// Now we can build a full multiaddress to reach this host
	// by encapsulating both addresses:
Jeromy's avatar
Jeromy committed
65
	addr := basicHost.Addrs()[0]
Hector Sanjuan's avatar
Hector Sanjuan committed
66
67
68
69
70
71
	fullAddr := addr.Encapsulate(hostAddr)
	log.Printf("I am %s\n", fullAddr)
	if secio {
		log.Printf("Now run \"./echo -l %d -d %s -secio\" on a different terminal\n", listenPort+1, fullAddr)
	} else {
		log.Printf("Now run \"./echo -l %d -d %s\" on a different terminal\n", listenPort+1, fullAddr)
Jeromy's avatar
Jeromy committed
72
73
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
74
	return basicHost, nil
Jeromy's avatar
Jeromy committed
75
76
77
}

func main() {
Hector Sanjuan's avatar
Hector Sanjuan committed
78
79
80
	// LibP2P code uses golog to log messages. They log with different
	// string IDs (i.e. "swarm"). We can control the verbosity level for
	// all loggers with:
Hector Sanjuan's avatar
Hector Sanjuan committed
81
	golog.SetAllLoggers(gologging.INFO) // Change to DEBUG for extra info
Hector Sanjuan's avatar
Hector Sanjuan committed
82
83

	// Parse options from the command line
Jeromy's avatar
Jeromy committed
84
85
	listenF := flag.Int("l", 0, "wait for incoming connections")
	target := flag.String("d", "", "target peer to dial")
Jeromy's avatar
Jeromy committed
86
	secio := flag.Bool("secio", false, "enable secio")
87
	seed := flag.Int64("seed", 0, "set random seed for id generation")
Jeromy's avatar
Jeromy committed
88
89
	flag.Parse()

Hector Sanjuan's avatar
Hector Sanjuan committed
90
91
92
93
	if *listenF == 0 {
		log.Fatal("Please provide a port to bind on with -l")
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
94
	// Make a host that listens on the given multiaddress
95
	ha, err := makeBasicHost(*listenF, *secio, *seed)
Jeromy's avatar
Jeromy committed
96
97
98
99
	if err != nil {
		log.Fatal(err)
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
100
101
	// Set a stream handler on host A. /echo/1.0.0 is
	// a user-defined protocol name.
Jeromy's avatar
Jeromy committed
102
	ha.SetStreamHandler("/echo/1.0.0", func(s net.Stream) {
Hector Sanjuan's avatar
Hector Sanjuan committed
103
		log.Println("Got a new stream!")
Steven Allen's avatar
Steven Allen committed
104
105
106
107
108
109
		if err := doEcho(s); err != nil {
			log.Println(err)
			s.Reset()
		} else {
			s.Close()
		}
Jeromy's avatar
Jeromy committed
110
111
112
	})

	if *target == "" {
Lars Gierth's avatar
Lars Gierth committed
113
		log.Println("listening for connections")
Jeromy's avatar
Jeromy committed
114
		select {} // hang forever
Jeromy's avatar
Jeromy committed
115
	}
Hector Sanjuan's avatar
Hector Sanjuan committed
116
	/**** This is where the listener code ends ****/
Jeromy's avatar
Jeromy committed
117

Hector Sanjuan's avatar
Hector Sanjuan committed
118
119
	// The following code extracts target's the peer ID from the
	// given multiaddress
Jeromy's avatar
Jeromy committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
	ipfsaddr, err := ma.NewMultiaddr(*target)
	if err != nil {
		log.Fatalln(err)
	}

	pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS)
	if err != nil {
		log.Fatalln(err)
	}

	peerid, err := peer.IDB58Decode(pid)
	if err != nil {
		log.Fatalln(err)
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
135
136
137
138
139
	// Decapsulate the /ipfs/<peerID> part from the target
	// /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d>
	targetPeerAddr, _ := ma.NewMultiaddr(
		fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid)))
	targetAddr := ipfsaddr.Decapsulate(targetPeerAddr)
Jeromy's avatar
Jeromy committed
140

Hector Sanjuan's avatar
Hector Sanjuan committed
141
142
	// We have a peer ID and a targetAddr so we add it to the peerstore
	// so LibP2P knows how to contact it
143
	ha.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL)
Jeromy's avatar
Jeromy committed
144

Lars Gierth's avatar
Lars Gierth committed
145
	log.Println("opening stream")
Jeromy's avatar
Jeromy committed
146
	// make a new stream from host B to host A
Hector Sanjuan's avatar
Hector Sanjuan committed
147
148
	// it should be handled on host A by the handler we set above because
	// we use the same /echo/1.0.0 protocol
Lars Gierth's avatar
Lars Gierth committed
149
	s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0")
Jeromy's avatar
Jeromy committed
150
151
152
153
	if err != nil {
		log.Fatalln(err)
	}

Hector Sanjuan's avatar
Hector Sanjuan committed
154
	_, err = s.Write([]byte("Hello, world!\n"))
Jeromy's avatar
Jeromy committed
155
156
157
158
	if err != nil {
		log.Fatalln(err)
	}

Jeromy's avatar
Jeromy committed
159
160
161
162
163
	out, err := ioutil.ReadAll(s)
	if err != nil {
		log.Fatalln(err)
	}

Lars Gierth's avatar
Lars Gierth committed
164
	log.Printf("read reply: %q\n", out)
Jeromy's avatar
Jeromy committed
165
}
Jeromy's avatar
Jeromy committed
166

Hector Sanjuan's avatar
Hector Sanjuan committed
167
// doEcho reads a line of data a stream and writes it back
Steven Allen's avatar
Steven Allen committed
168
func doEcho(s net.Stream) error {
Hector Sanjuan's avatar
Hector Sanjuan committed
169
170
	buf := bufio.NewReader(s)
	str, err := buf.ReadString('\n')
Lars Gierth's avatar
Lars Gierth committed
171
	if err != nil {
Steven Allen's avatar
Steven Allen committed
172
		return err
Lars Gierth's avatar
Lars Gierth committed
173
	}
Jeromy's avatar
Jeromy committed
174

Hector Sanjuan's avatar
Hector Sanjuan committed
175
176
	log.Printf("read: %s\n", str)
	_, err = s.Write([]byte(str))
Steven Allen's avatar
Steven Allen committed
177
	return err
Jeromy's avatar
Jeromy committed
178
}