versionExchange: first stab in the dark
Henry committed
Oct 16, 2014 at 11:35 UTC
6b0440c0502be4f44a1f33433e1e0e5e842ef294
5 files changed
+160
net/swarm/conn.go
+56
@@ -7,7 +7,9 @@ import (
7
spipe "github.com/jbenet/go-ipfs/crypto/spipe"
8
conn "github.com/jbenet/go-ipfs/net/conn"
9
msg "github.com/jbenet/go-ipfs/net/message"
10
+ version "github.com/jbenet/go-ipfs/net/version"
11
12
+ proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
13
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
15
)
@@ -109,6 +111,10 @@ func (s *Swarm) connSetup(c *conn.Conn) error {
111
// add address of connection to Peer. Maybe it should happen in connSecure.
112
c.Peer.AddAddress(c.Addr)
113
114
+ if err := s.connVersionExchange(c); err != nil {
115
+ return fmt.Errorf("Conn version exchange error: %v", err)
116
+ }
117
+
118
// add to conns
119
s.connsLock.Lock()
120
if _, ok := s.conns[c.Peer.Key()]; ok {
@@ -152,6 +158,56 @@ func (s *Swarm) connSecure(c *conn.Conn) error {
158
return nil
159
}
160
161
+// connVersionExchange exchanges local and remote versions and compares them
162
+// closes remote and returns an error in case of major difference
163
+func (s *Swarm) connVersionExchange(remote *conn.Conn) error {
164
+ var remoteVersion, myVersion *version.SemVer
165
+ myVersion = version.Current()
166
+
167
+ myVersionMsg, err := msg.FromObject(s.local, myVersion)
168
+ if err != nil {
169
+ return fmt.Errorf("connVersionExchange: could not prepare local version: %q", err)
170
+ }
171
+
172
+ var gotTheirs, sendMine bool
173
+ for {
174
+ if gotTheirs && sendMine {
175
+ break
176
+ }
177
+
178
+ select {
179
+ case <-s.ctx.Done():
180
+ // close Conn.
181
+ remote.Close()
182
+ return nil // BUG(cryptix): should this be an error?
183
+
184
+ case <-remote.Closed:
185
+ return errors.New("remote closed connection during version exchange")
186
+
187
+ case remote.Secure.Out <- myVersionMsg.Data():
188
+ log.Debug("[peer: %s] Send my version(%s) to %s", s.local, myVersion, remote.Peer)
189
+ sendMine = true
190
+
191
+ case data, ok := <-remote.Secure.In:
192
+ if !ok {
193
+ return fmt.Errorf("Error retrieving from conn: %v", remote.Peer)
194
+ }
195
+
196
+ log.Debug("[peer: %s] Received message [from = %s]", s.local, remote.Peer)
197
+
198
+ remoteVersion = new(version.SemVer)
199
+ err = proto.Unmarshal(data, remoteVersion)
200
+ if err != nil {
201
+ s.Close()
202
+ return fmt.Errorf("connSetup: could not decode remote version: %q", err)
203
+ }
204
+ gotTheirs = true
205
+ }
206
+ }
207
+
208
+ return errors.New("not yet")
209
+}
210
+
211
// Handles the unwrapping + sending of messages to the right connection.
212
func (s *Swarm) fanOut() {
213
for {
net/version/Makefile
new
+8
@@ -0,0 +1,8 @@
1
+
2
+all: semver.pb.go
3
+
4
+semver.pb.go: semver.proto
5
+ protoc --gogo_out=. --proto_path=../../../../../:/usr/include/google:. $<
6
+
7
+clean:
8
+ rm semver.pb.go
net/version/semver.pb.go
new
+56
@@ -0,0 +1,56 @@
1
+// Code generated by protoc-gen-gogo.
2
+// source: semver.proto
3
+// DO NOT EDIT!
4
+
5
+/*
6
+Package version is a generated protocol buffer package.
7
+
8
+It is generated from these files:
9
+ semver.proto
10
+
11
+It has these top-level messages:
12
+ SemVer
13
+*/
14
+package version
15
+
16
+import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
17
+import math "math"
18
+
19
+// Reference imports to suppress errors if they are not otherwise used.
20
+var _ = proto.Marshal
21
+var _ = math.Inf
22
+
23
+type SemVer struct {
24
+ Major *int64 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"`
25
+ Minor *int64 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"`
26
+ Patch *int64 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"`
27
+ XXX_unrecognized []byte `json:"-"`
28
+}
29
+
30
+func (m *SemVer) Reset() { *m = SemVer{} }
31
+func (m *SemVer) String() string { return proto.CompactTextString(m) }
32
+func (*SemVer) ProtoMessage() {}
33
+
34
+func (m *SemVer) GetMajor() int64 {
35
+ if m != nil && m.Major != nil {
36
+ return *m.Major
37
+ }
38
+ return 0
39
+}
40
+
41
+func (m *SemVer) GetMinor() int64 {
42
+ if m != nil && m.Minor != nil {
43
+ return *m.Minor
44
+ }
45
+ return 0
46
+}
47
+
48
+func (m *SemVer) GetPatch() int64 {
49
+ if m != nil && m.Patch != nil {
50
+ return *m.Patch
51
+ }
52
+ return 0
53
+}
54
+
55
+func init() {
56
+}
net/version/semver.proto
new
+8
@@ -0,0 +1,8 @@
1
+package version;
2
+
3
+message SemVer {
4
+ optional int64 major = 1;
5
+ optional int64 minor = 2;
6
+ optional int64 patch = 3;
7
+ // BUG(cryptix): do we need PreRelease and Metadata too?
8
+}
net/version/version.go
new
+32
@@ -0,0 +1,32 @@
1
+package version
2
+
3
+import semver "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
4
+
5
+var currentVersion = semver.Version{
6
+ Major: 0,
7
+ Minor: 1,
8
+ Patch: 0,
9
+}
10
+
11
+// Current returns the current protocol version as a protobuf message
12
+func Current() *SemVer {
13
+ return toPBSemVer(currentVersion)
14
+}
15
+
16
+// toPBSemVar converts a coreos/semver to our protobuf SemVer
17
+func toPBSemVer(in semver.Version) (out *SemVer) {
18
+ return &SemVer{
19
+ Major: &in.Major,
20
+ Minor: &in.Minor,
21
+ Patch: &in.Patch,
22
+ }
23
+}
24
+
25
+// toPBSemVar converts our protobuf SemVer to a coreos/semver
26
+func fromPBSemVer(in SemVer) *semver.Version {
27
+ return &semver.Version{
28
+ Major: *in.Major,
29
+ Minor: *in.Minor,
30
+ Patch: *in.Patch,
31
+ }
32
+}