Browse Source

Merge pull request #308 from mrjana/overlay

Overlay Driver
Madhu Venugopal 10 years ago
parent
commit
e0cb591489
100 changed files with 24453 additions and 25 deletions
  1. 18 21
      libnetwork/Godeps/Godeps.json
  2. 22 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore
  3. 20 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/LICENSE
  4. 68 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/README.md
  5. 12 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/const_unix.go
  6. 13 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/const_windows.go
  7. 239 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem.go
  8. 100 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal.go
  9. 46 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go
  10. 95 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_test.go
  11. 115 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics.go
  12. 262 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go
  13. 52 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink.go
  14. 120 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink_test.go
  15. 95 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start.go
  16. 110 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start_test.go
  17. 154 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd.go
  18. 105 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd_test.go
  19. 142 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite.go
  20. 101 0
      libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go
  21. 143 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/0doc.go
  22. 174 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/README.md
  23. 319 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/bench_test.go
  24. 786 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/binc.go
  25. 1002 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/codecs_test.go
  26. 1048 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/decode.go
  27. 1001 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/encode.go
  28. 75 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/ext_dep_test.go
  29. 589 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/helper.go
  30. 127 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/helper_internal.go
  31. 816 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack.go
  32. 110 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py
  33. 152 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/rpc.go
  34. 461 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/simple.go
  35. 193 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/time.go
  36. 103 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/z_helper_test.go
  37. 25 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/.gitignore
  38. 354 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/LICENSE
  39. 14 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/Makefile
  40. 137 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/README.md
  41. 100 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/broadcast.go
  42. 27 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/broadcast_test.go
  43. 209 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/config.go
  44. 10 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/conflict_delegate.go
  45. 36 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/delegate.go
  46. 61 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/event_delegate.go
  47. 89 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/integ_test.go
  48. 144 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/keyring.go
  49. 154 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/keyring_test.go
  50. 525 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/memberlist.go
  51. 1144 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/memberlist_test.go
  52. 13 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/merge_delegate.go
  53. 852 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/net.go
  54. 476 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/net_test.go
  55. 167 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/queue.go
  56. 172 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/queue_test.go
  57. 198 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/security.go
  58. 70 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/security_test.go
  59. 916 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/state.go
  60. 1039 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/state_test.go
  61. 28 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/test/setup_subnet.sh
  62. 6 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/todo.md
  63. 325 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/util.go
  64. 293 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/util_test.go
  65. 27 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/broadcast.go
  66. 32 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/broadcast_test.go
  67. 80 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce.go
  68. 68 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_member.go
  69. 185 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_member_test.go
  70. 140 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_test.go
  71. 52 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_user.go
  72. 102 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_user_test.go
  73. 234 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/config.go
  74. 12 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/config_test.go
  75. 13 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/conflict_delegate.go
  76. 247 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/delegate.go
  77. 213 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/delegate_test.go
  78. 168 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event.go
  79. 21 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event_delegate.go
  80. 211 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event_test.go
  81. 312 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/internal_query.go
  82. 89 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/internal_query_test.go
  83. 166 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/keymanager.go
  84. 272 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/keymanager_test.go
  85. 45 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/lamport.go
  86. 39 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/lamport_test.go
  87. 35 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/merge_delegate.go
  88. 147 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/messages.go
  89. 58 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/messages_test.go
  90. 210 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/query.go
  91. 138 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/query_test.go
  92. 1598 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf.go
  93. 442 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf_internals_test.go
  94. 1647 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf_test.go
  95. 500 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/snapshot.go
  96. 374 0
      libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/snapshot_test.go
  97. 1 1
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go
  98. 1 1
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go
  99. 1 1
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go
  100. 1 1
      libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go

+ 18 - 21
libnetwork/Godeps/Godeps.json

@@ -1,6 +1,6 @@
 {
 	"ImportPath": "github.com/docker/libnetwork",
-	"GoVersion": "go1.4.1",
+	"GoVersion": "go1.4.2",
 	"Packages": [
 		"./..."
 	],
@@ -15,16 +15,15 @@
 			"Comment": "v0.6.4-12-g467d9d5",
 			"Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
 		},
+		{
+			"ImportPath": "github.com/armon/go-metrics",
+			"Rev": "eb0af217e5e9747e41dd5303755356b62d28e3ec"
+		},
 		{
 			"ImportPath": "github.com/coreos/go-etcd/etcd",
 			"Comment": "v2.0.0-7-g73a8ef7",
 			"Rev": "73a8ef737e8ea002281a28b4cb92a1de121ad4c6"
 		},
-		{
-			"ImportPath": "github.com/deckarep/golang-set",
-			"Comment": "v1-26-gef32fa3",
-			"Rev": "ef32fa3046d9f249d399f98ebaf9be944430fd1d"
-		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/homedir",
 			"Comment": "v1.4.1-4106-g637023a",
@@ -70,26 +69,11 @@
 			"Comment": "v1.4.1-4106-g637023a",
 			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
-		{
-			"ImportPath": "github.com/docker/docker/api/client",
-			"Comment": "v1.4.1-4106-g637023a",
-			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
-		},
 		{
 			"ImportPath": "github.com/docker/libcontainer/user",
 			"Comment": "v1.4.0-495-g3e66118",
 			"Rev": "3e661186ba24f259d3860f067df052c7f6904bee"
 		},
-		{
-			"ImportPath": "github.com/docker/swarm/discovery",
-			"Comment": "v0.3.0-rc2",
-			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
-		},
-		{
-			"ImportPath": "github.com/docker/swarm/pkg/store",
-			"Comment": "v0.3.0-rc2",
-			"Rev": "a5b2e57496762cb6971eb65809b2e428cb179719"
-		},
 		{
 			"ImportPath": "github.com/docker/libkv",
 			"Rev": "ab16c3d4a8785a9877c62d0b11ea4441cf09120c"
@@ -112,6 +96,19 @@
 			"Comment": "v0.5.0rc1-66-g954aec6",
 			"Rev": "954aec66231b79c161a4122b023fbcad13047f79"
 		},
+		{
+			"ImportPath": "github.com/hashicorp/go-msgpack/codec",
+			"Rev": "71c2886f5a673a35f909803f38ece5810165097b"
+		},
+		{
+			"ImportPath": "github.com/hashicorp/memberlist",
+			"Rev": "9a1e242e454d2443df330bdd51a436d5a9058fc4"
+		},
+		{
+			"ImportPath": "github.com/hashicorp/serf/serf",
+			"Comment": "v0.6.4",
+			"Rev": "7151adcef72687bf95f451a2e0ba15cb19412bf2"
+		},
 		{
 			"ImportPath": "github.com/samuel/go-zookeeper/zk",
 			"Rev": "d0e0d8e11f318e000a8cc434616d69e329edc374"

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/.gitignore

@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Armon Dadgar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 68 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/README.md

@@ -0,0 +1,68 @@
+go-metrics
+==========
+
+This library provides a `metrics` package which can be used to instrument code,
+expose application metrics, and profile runtime performance in a flexible manner.
+
+Sinks
+=====
+
+The `metrics` package makes use of a `MetricSink` interface to support delivery
+to any type of backend. Currently the following sinks are provided:
+
+* StatsiteSink : Sinks to a statsite instance (TCP)
+* StatsdSink: Sinks to a statsd / statsite instance (UDP)
+* InmemSink : Provides in-memory aggregation, can be used to export stats
+* FanoutSink : Sinks to multiple sinks. Enables writing to multiple statsite instances for example.
+* BlackholeSink : Sinks to nowhere
+
+In addition to the sinks, the `InmemSignal` can be used to catch a signal,
+and dump a formatted output of recent metrics. For example, when a process gets
+a SIGUSR1, it can dump to stderr recent performance metrics for debugging.
+
+Examples
+========
+
+Here is an example of using the package:
+
+    func SlowMethod() {
+        // Profiling the runtime of a method
+        defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
+    }
+
+    // Configure a statsite sink as the global metrics sink
+    sink, _ := metrics.NewStatsiteSink("statsite:8125")
+    metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)
+
+    // Emit a Key/Value pair
+    metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
+
+
+Here is an example of setting up an signal handler:
+
+    // Setup the inmem sink and signal handler
+    inm := NewInmemSink(10*time.Second, time.Minute)
+    sig := DefaultInmemSignal(inm)
+    metrics.NewGlobal(metrics.DefaultConfig("service-name"), inm)
+
+    // Run some code
+    inm.SetGauge([]string{"foo"}, 42)
+	inm.EmitKey([]string{"bar"}, 30)
+
+	inm.IncrCounter([]string{"baz"}, 42)
+	inm.IncrCounter([]string{"baz"}, 1)
+	inm.IncrCounter([]string{"baz"}, 80)
+
+	inm.AddSample([]string{"method", "wow"}, 42)
+	inm.AddSample([]string{"method", "wow"}, 100)
+	inm.AddSample([]string{"method", "wow"}, 22)
+
+    ....
+
+When a signal comes in, output like the following will be dumped to stderr:
+
+    [2014-01-28 14:57:33.04 -0800 PST][G] 'foo': 42.000
+    [2014-01-28 14:57:33.04 -0800 PST][P] 'bar': 30.000
+	[2014-01-28 14:57:33.04 -0800 PST][C] 'baz': Count: 3 Min: 1.000 Mean: 41.000 Max: 80.000 Stddev: 39.509
+    [2014-01-28 14:57:33.04 -0800 PST][S] 'method.wow': Count: 3 Min: 22.000 Mean: 54.667 Max: 100.000 Stddev: 40.513
+

+ 12 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/const_unix.go

@@ -0,0 +1,12 @@
+// +build !windows
+
+package metrics
+
+import (
+	"syscall"
+)
+
+const (
+	// DefaultSignal is used with DefaultInmemSignal
+	DefaultSignal = syscall.SIGUSR1
+)

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/const_windows.go

@@ -0,0 +1,13 @@
+// +build windows
+
+package metrics
+
+import (
+	"syscall"
+)
+
+const (
+	// DefaultSignal is used with DefaultInmemSignal
+	// Windows has no SIGUSR1, use SIGBREAK
+	DefaultSignal = syscall.Signal(21)
+)

+ 239 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem.go

@@ -0,0 +1,239 @@
+package metrics
+
+import (
+	"fmt"
+	"math"
+	"strings"
+	"sync"
+	"time"
+)
+
+// InmemSink provides a MetricSink that does in-memory aggregation
+// without sending metrics over a network. It can be embedded within
+// an application to provide profiling information.
+type InmemSink struct {
+	// How long is each aggregation interval
+	interval time.Duration
+
+	// Retain controls how many metrics interval we keep
+	retain time.Duration
+
+	// maxIntervals is the maximum length of intervals.
+	// It is retain / interval.
+	maxIntervals int
+
+	// intervals is a slice of the retained intervals
+	intervals    []*IntervalMetrics
+	intervalLock sync.RWMutex
+}
+
+// IntervalMetrics stores the aggregated metrics
+// for a specific interval
+type IntervalMetrics struct {
+	sync.RWMutex
+
+	// The start time of the interval
+	Interval time.Time
+
+	// Gauges maps the key to the last set value
+	Gauges map[string]float32
+
+	// Points maps the string to the list of emitted values
+	// from EmitKey
+	Points map[string][]float32
+
+	// Counters maps the string key to a sum of the counter
+	// values
+	Counters map[string]*AggregateSample
+
+	// Samples maps the key to an AggregateSample,
+	// which has the rolled up view of a sample
+	Samples map[string]*AggregateSample
+}
+
+// NewIntervalMetrics creates a new IntervalMetrics for a given interval
+func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
+	return &IntervalMetrics{
+		Interval: intv,
+		Gauges:   make(map[string]float32),
+		Points:   make(map[string][]float32),
+		Counters: make(map[string]*AggregateSample),
+		Samples:  make(map[string]*AggregateSample),
+	}
+}
+
+// AggregateSample is used to hold aggregate metrics
+// about a sample
+type AggregateSample struct {
+	Count int     // The count of emitted pairs
+	Sum   float64 // The sum of values
+	SumSq float64 // The sum of squared values
+	Min   float64 // Minimum value
+	Max   float64 // Maximum value
+}
+
+// Computes a Stddev of the values
+func (a *AggregateSample) Stddev() float64 {
+	num := (float64(a.Count) * a.SumSq) - math.Pow(a.Sum, 2)
+	div := float64(a.Count * (a.Count - 1))
+	if div == 0 {
+		return 0
+	}
+	return math.Sqrt(num / div)
+}
+
+// Computes a mean of the values
+func (a *AggregateSample) Mean() float64 {
+	if a.Count == 0 {
+		return 0
+	}
+	return a.Sum / float64(a.Count)
+}
+
+// Ingest is used to update a sample
+func (a *AggregateSample) Ingest(v float64) {
+	a.Count++
+	a.Sum += v
+	a.SumSq += (v * v)
+	if v < a.Min || a.Count == 1 {
+		a.Min = v
+	}
+	if v > a.Max || a.Count == 1 {
+		a.Max = v
+	}
+}
+
+func (a *AggregateSample) String() string {
+	if a.Count == 0 {
+		return "Count: 0"
+	} else if a.Stddev() == 0 {
+		return fmt.Sprintf("Count: %d Sum: %0.3f", a.Count, a.Sum)
+	} else {
+		return fmt.Sprintf("Count: %d Min: %0.3f Mean: %0.3f Max: %0.3f Stddev: %0.3f Sum: %0.3f",
+			a.Count, a.Min, a.Mean(), a.Max, a.Stddev(), a.Sum)
+	}
+}
+
+// NewInmemSink is used to construct a new in-memory sink.
+// Uses an aggregation interval and maximum retention period.
+func NewInmemSink(interval, retain time.Duration) *InmemSink {
+	i := &InmemSink{
+		interval:     interval,
+		retain:       retain,
+		maxIntervals: int(retain / interval),
+	}
+	i.intervals = make([]*IntervalMetrics, 0, i.maxIntervals)
+	return i
+}
+
+func (i *InmemSink) SetGauge(key []string, val float32) {
+	k := i.flattenKey(key)
+	intv := i.getInterval()
+
+	intv.Lock()
+	defer intv.Unlock()
+	intv.Gauges[k] = val
+}
+
+func (i *InmemSink) EmitKey(key []string, val float32) {
+	k := i.flattenKey(key)
+	intv := i.getInterval()
+
+	intv.Lock()
+	defer intv.Unlock()
+	vals := intv.Points[k]
+	intv.Points[k] = append(vals, val)
+}
+
+func (i *InmemSink) IncrCounter(key []string, val float32) {
+	k := i.flattenKey(key)
+	intv := i.getInterval()
+
+	intv.Lock()
+	defer intv.Unlock()
+
+	agg := intv.Counters[k]
+	if agg == nil {
+		agg = &AggregateSample{}
+		intv.Counters[k] = agg
+	}
+	agg.Ingest(float64(val))
+}
+
+func (i *InmemSink) AddSample(key []string, val float32) {
+	k := i.flattenKey(key)
+	intv := i.getInterval()
+
+	intv.Lock()
+	defer intv.Unlock()
+
+	agg := intv.Samples[k]
+	if agg == nil {
+		agg = &AggregateSample{}
+		intv.Samples[k] = agg
+	}
+	agg.Ingest(float64(val))
+}
+
+// Data is used to retrieve all the aggregated metrics
+// Intervals may be in use, and a read lock should be acquired
+func (i *InmemSink) Data() []*IntervalMetrics {
+	// Get the current interval, forces creation
+	i.getInterval()
+
+	i.intervalLock.RLock()
+	defer i.intervalLock.RUnlock()
+
+	intervals := make([]*IntervalMetrics, len(i.intervals))
+	copy(intervals, i.intervals)
+	return intervals
+}
+
+func (i *InmemSink) getExistingInterval(intv time.Time) *IntervalMetrics {
+	i.intervalLock.RLock()
+	defer i.intervalLock.RUnlock()
+
+	n := len(i.intervals)
+	if n > 0 && i.intervals[n-1].Interval == intv {
+		return i.intervals[n-1]
+	}
+	return nil
+}
+
+func (i *InmemSink) createInterval(intv time.Time) *IntervalMetrics {
+	i.intervalLock.Lock()
+	defer i.intervalLock.Unlock()
+
+	// Check for an existing interval
+	n := len(i.intervals)
+	if n > 0 && i.intervals[n-1].Interval == intv {
+		return i.intervals[n-1]
+	}
+
+	// Add the current interval
+	current := NewIntervalMetrics(intv)
+	i.intervals = append(i.intervals, current)
+	n++
+
+	// Truncate the intervals if they are too long
+	if n >= i.maxIntervals {
+		copy(i.intervals[0:], i.intervals[n-i.maxIntervals:])
+		i.intervals = i.intervals[:i.maxIntervals]
+	}
+	return current
+}
+
+// getInterval returns the current interval to write to
+func (i *InmemSink) getInterval() *IntervalMetrics {
+	intv := time.Now().Truncate(i.interval)
+	if m := i.getExistingInterval(intv); m != nil {
+		return m
+	}
+	return i.createInterval(intv)
+}
+
+// Flattens the key for formatting, removes spaces
+func (i *InmemSink) flattenKey(parts []string) string {
+	joined := strings.Join(parts, ".")
+	return strings.Replace(joined, " ", "_", -1)
+}

+ 100 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal.go

@@ -0,0 +1,100 @@
+package metrics
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"os/signal"
+	"sync"
+	"syscall"
+)
+
+// InmemSignal is used to listen for a given signal, and when received,
+// to dump the current metrics from the InmemSink to an io.Writer
+type InmemSignal struct {
+	signal syscall.Signal
+	inm    *InmemSink
+	w      io.Writer
+	sigCh  chan os.Signal
+
+	stop     bool
+	stopCh   chan struct{}
+	stopLock sync.Mutex
+}
+
+// NewInmemSignal creates a new InmemSignal which listens for a given signal,
+// and dumps the current metrics out to a writer
+func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
+	i := &InmemSignal{
+		signal: sig,
+		inm:    inmem,
+		w:      w,
+		sigCh:  make(chan os.Signal, 1),
+		stopCh: make(chan struct{}),
+	}
+	signal.Notify(i.sigCh, sig)
+	go i.run()
+	return i
+}
+
+// DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1
+// and writes output to stderr. Windows uses SIGBREAK
+func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
+	return NewInmemSignal(inmem, DefaultSignal, os.Stderr)
+}
+
+// Stop is used to stop the InmemSignal from listening
+func (i *InmemSignal) Stop() {
+	i.stopLock.Lock()
+	defer i.stopLock.Unlock()
+
+	if i.stop {
+		return
+	}
+	i.stop = true
+	close(i.stopCh)
+	signal.Stop(i.sigCh)
+}
+
+// run is a long running routine that handles signals
+func (i *InmemSignal) run() {
+	for {
+		select {
+		case <-i.sigCh:
+			i.dumpStats()
+		case <-i.stopCh:
+			return
+		}
+	}
+}
+
+// dumpStats is used to dump the data to output writer
+func (i *InmemSignal) dumpStats() {
+	buf := bytes.NewBuffer(nil)
+
+	data := i.inm.Data()
+	// Skip the last period which is still being aggregated
+	for i := 0; i < len(data)-1; i++ {
+		intv := data[i]
+		intv.RLock()
+		for name, val := range intv.Gauges {
+			fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val)
+		}
+		for name, vals := range intv.Points {
+			for _, val := range vals {
+				fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
+			}
+		}
+		for name, agg := range intv.Counters {
+			fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg)
+		}
+		for name, agg := range intv.Samples {
+			fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg)
+		}
+		intv.RUnlock()
+	}
+
+	// Write out the bytes
+	i.w.Write(buf.Bytes())
+}

+ 46 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_signal_test.go

@@ -0,0 +1,46 @@
+package metrics
+
+import (
+	"bytes"
+	"os"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestInmemSignal(t *testing.T) {
+	buf := bytes.NewBuffer(nil)
+	inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
+	sig := NewInmemSignal(inm, syscall.SIGUSR1, buf)
+	defer sig.Stop()
+
+	inm.SetGauge([]string{"foo"}, 42)
+	inm.EmitKey([]string{"bar"}, 42)
+	inm.IncrCounter([]string{"baz"}, 42)
+	inm.AddSample([]string{"wow"}, 42)
+
+	// Wait for period to end
+	time.Sleep(15 * time.Millisecond)
+
+	// Send signal!
+	syscall.Kill(os.Getpid(), syscall.SIGUSR1)
+
+	// Wait for flush
+	time.Sleep(10 * time.Millisecond)
+
+	// Check the output
+	out := string(buf.Bytes())
+	if !strings.Contains(out, "[G] 'foo': 42") {
+		t.Fatalf("bad: %v", out)
+	}
+	if !strings.Contains(out, "[P] 'bar': 42") {
+		t.Fatalf("bad: %v", out)
+	}
+	if !strings.Contains(out, "[C] 'baz': Count: 1 Sum: 42") {
+		t.Fatalf("bad: %v", out)
+	}
+	if !strings.Contains(out, "[S] 'wow': Count: 1 Sum: 42") {
+		t.Fatalf("bad: %v", out)
+	}
+}

+ 95 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/inmem_test.go

@@ -0,0 +1,95 @@
+package metrics
+
+import (
+	"math"
+	"testing"
+	"time"
+)
+
+func TestInmemSink(t *testing.T) {
+	inm := NewInmemSink(10*time.Millisecond, 50*time.Millisecond)
+
+	data := inm.Data()
+	if len(data) != 1 {
+		t.Fatalf("bad: %v", data)
+	}
+
+	// Add data points
+	inm.SetGauge([]string{"foo", "bar"}, 42)
+	inm.EmitKey([]string{"foo", "bar"}, 42)
+	inm.IncrCounter([]string{"foo", "bar"}, 20)
+	inm.IncrCounter([]string{"foo", "bar"}, 22)
+	inm.AddSample([]string{"foo", "bar"}, 20)
+	inm.AddSample([]string{"foo", "bar"}, 22)
+
+	data = inm.Data()
+	if len(data) != 1 {
+		t.Fatalf("bad: %v", data)
+	}
+
+	intvM := data[0]
+	intvM.RLock()
+
+	if time.Now().Sub(intvM.Interval) > 10*time.Millisecond {
+		t.Fatalf("interval too old")
+	}
+	if intvM.Gauges["foo.bar"] != 42 {
+		t.Fatalf("bad val: %v", intvM.Gauges)
+	}
+	if intvM.Points["foo.bar"][0] != 42 {
+		t.Fatalf("bad val: %v", intvM.Points)
+	}
+
+	agg := intvM.Counters["foo.bar"]
+	if agg.Count != 2 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.Sum != 42 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.SumSq != 884 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.Min != 20 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.Max != 22 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.Mean() != 21 {
+		t.Fatalf("bad val: %v", agg)
+	}
+	if agg.Stddev() != math.Sqrt(2) {
+		t.Fatalf("bad val: %v", agg)
+	}
+
+	if agg = intvM.Samples["foo.bar"]; agg == nil {
+		t.Fatalf("missing sample")
+	}
+
+	intvM.RUnlock()
+
+	for i := 1; i < 10; i++ {
+		time.Sleep(10 * time.Millisecond)
+		inm.SetGauge([]string{"foo", "bar"}, 42)
+		data = inm.Data()
+		if len(data) != min(i+1, 5) {
+			t.Fatalf("bad: %v", data)
+		}
+	}
+
+	// Should not exceed 5 intervals!
+	time.Sleep(10 * time.Millisecond)
+	inm.SetGauge([]string{"foo", "bar"}, 42)
+	data = inm.Data()
+	if len(data) != 5 {
+		t.Fatalf("bad: %v", data)
+	}
+}
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}

+ 115 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics.go

@@ -0,0 +1,115 @@
+package metrics
+
+import (
+	"runtime"
+	"time"
+)
+
+func (m *Metrics) SetGauge(key []string, val float32) {
+	if m.HostName != "" && m.EnableHostname {
+		key = insert(0, m.HostName, key)
+	}
+	if m.EnableTypePrefix {
+		key = insert(0, "gauge", key)
+	}
+	if m.ServiceName != "" {
+		key = insert(0, m.ServiceName, key)
+	}
+	m.sink.SetGauge(key, val)
+}
+
+func (m *Metrics) EmitKey(key []string, val float32) {
+	if m.EnableTypePrefix {
+		key = insert(0, "kv", key)
+	}
+	if m.ServiceName != "" {
+		key = insert(0, m.ServiceName, key)
+	}
+	m.sink.EmitKey(key, val)
+}
+
+func (m *Metrics) IncrCounter(key []string, val float32) {
+	if m.EnableTypePrefix {
+		key = insert(0, "counter", key)
+	}
+	if m.ServiceName != "" {
+		key = insert(0, m.ServiceName, key)
+	}
+	m.sink.IncrCounter(key, val)
+}
+
+func (m *Metrics) AddSample(key []string, val float32) {
+	if m.EnableTypePrefix {
+		key = insert(0, "sample", key)
+	}
+	if m.ServiceName != "" {
+		key = insert(0, m.ServiceName, key)
+	}
+	m.sink.AddSample(key, val)
+}
+
+func (m *Metrics) MeasureSince(key []string, start time.Time) {
+	if m.EnableTypePrefix {
+		key = insert(0, "timer", key)
+	}
+	if m.ServiceName != "" {
+		key = insert(0, m.ServiceName, key)
+	}
+	now := time.Now()
+	elapsed := now.Sub(start)
+	msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
+	m.sink.AddSample(key, msec)
+}
+
+// Periodically collects runtime stats to publish
+func (m *Metrics) collectStats() {
+	for {
+		time.Sleep(m.ProfileInterval)
+		m.emitRuntimeStats()
+	}
+}
+
+// Emits various runtime statsitics
+func (m *Metrics) emitRuntimeStats() {
+	// Export number of Goroutines
+	numRoutines := runtime.NumGoroutine()
+	m.SetGauge([]string{"runtime", "num_goroutines"}, float32(numRoutines))
+
+	// Export memory stats
+	var stats runtime.MemStats
+	runtime.ReadMemStats(&stats)
+	m.SetGauge([]string{"runtime", "alloc_bytes"}, float32(stats.Alloc))
+	m.SetGauge([]string{"runtime", "sys_bytes"}, float32(stats.Sys))
+	m.SetGauge([]string{"runtime", "malloc_count"}, float32(stats.Mallocs))
+	m.SetGauge([]string{"runtime", "free_count"}, float32(stats.Frees))
+	m.SetGauge([]string{"runtime", "heap_objects"}, float32(stats.HeapObjects))
+	m.SetGauge([]string{"runtime", "total_gc_pause_ns"}, float32(stats.PauseTotalNs))
+	m.SetGauge([]string{"runtime", "total_gc_runs"}, float32(stats.NumGC))
+
+	// Export info about the last few GC runs
+	num := stats.NumGC
+
+	// Handle wrap around
+	if num < m.lastNumGC {
+		m.lastNumGC = 0
+	}
+
+	// Ensure we don't scan more than 256
+	if num-m.lastNumGC >= 256 {
+		m.lastNumGC = num - 255
+	}
+
+	for i := m.lastNumGC; i < num; i++ {
+		pause := stats.PauseNs[i%256]
+		m.AddSample([]string{"runtime", "gc_pause_ns"}, float32(pause))
+	}
+	m.lastNumGC = num
+}
+
+// Inserts a string value at an index into the slice
+func insert(i int, v string, s []string) []string {
+	s = append(s, "")
+	copy(s[i+1:], s[i:])
+	s[i] = v
+	return s
+}

+ 262 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/metrics_test.go

@@ -0,0 +1,262 @@
+package metrics
+
+import (
+	"reflect"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func mockMetric() (*MockSink, *Metrics) {
+	m := &MockSink{}
+	met := &Metrics{sink: m}
+	return m, met
+}
+
+func TestMetrics_SetGauge(t *testing.T) {
+	m, met := mockMetric()
+	met.SetGauge([]string{"key"}, float32(1))
+	if m.keys[0][0] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.HostName = "test"
+	met.EnableHostname = true
+	met.SetGauge([]string{"key"}, float32(1))
+	if m.keys[0][0] != "test" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.EnableTypePrefix = true
+	met.SetGauge([]string{"key"}, float32(1))
+	if m.keys[0][0] != "gauge" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.ServiceName = "service"
+	met.SetGauge([]string{"key"}, float32(1))
+	if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+}
+
+func TestMetrics_EmitKey(t *testing.T) {
+	m, met := mockMetric()
+	met.EmitKey([]string{"key"}, float32(1))
+	if m.keys[0][0] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.EnableTypePrefix = true
+	met.EmitKey([]string{"key"}, float32(1))
+	if m.keys[0][0] != "kv" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.ServiceName = "service"
+	met.EmitKey([]string{"key"}, float32(1))
+	if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+}
+
+func TestMetrics_IncrCounter(t *testing.T) {
+	m, met := mockMetric()
+	met.IncrCounter([]string{"key"}, float32(1))
+	if m.keys[0][0] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.EnableTypePrefix = true
+	met.IncrCounter([]string{"key"}, float32(1))
+	if m.keys[0][0] != "counter" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.ServiceName = "service"
+	met.IncrCounter([]string{"key"}, float32(1))
+	if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+}
+
+func TestMetrics_AddSample(t *testing.T) {
+	m, met := mockMetric()
+	met.AddSample([]string{"key"}, float32(1))
+	if m.keys[0][0] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.EnableTypePrefix = true
+	met.AddSample([]string{"key"}, float32(1))
+	if m.keys[0][0] != "sample" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.ServiceName = "service"
+	met.AddSample([]string{"key"}, float32(1))
+	if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] != 1 {
+		t.Fatalf("")
+	}
+}
+
+func TestMetrics_MeasureSince(t *testing.T) {
+	m, met := mockMetric()
+	met.TimerGranularity = time.Millisecond
+	n := time.Now()
+	met.MeasureSince([]string{"key"}, n)
+	if m.keys[0][0] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] > 0.1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.TimerGranularity = time.Millisecond
+	met.EnableTypePrefix = true
+	met.MeasureSince([]string{"key"}, n)
+	if m.keys[0][0] != "timer" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] > 0.1 {
+		t.Fatalf("")
+	}
+
+	m, met = mockMetric()
+	met.TimerGranularity = time.Millisecond
+	met.ServiceName = "service"
+	met.MeasureSince([]string{"key"}, n)
+	if m.keys[0][0] != "service" || m.keys[0][1] != "key" {
+		t.Fatalf("")
+	}
+	if m.vals[0] > 0.1 {
+		t.Fatalf("")
+	}
+}
+
+func TestMetrics_EmitRuntimeStats(t *testing.T) {
+	runtime.GC()
+	m, met := mockMetric()
+	met.emitRuntimeStats()
+
+	if m.keys[0][0] != "runtime" || m.keys[0][1] != "num_goroutines" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[0] <= 1 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[1][0] != "runtime" || m.keys[1][1] != "alloc_bytes" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[1] <= 100000 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[2][0] != "runtime" || m.keys[2][1] != "sys_bytes" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[2] <= 100000 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[3][0] != "runtime" || m.keys[3][1] != "malloc_count" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[3] <= 100 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[4][0] != "runtime" || m.keys[4][1] != "free_count" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[4] <= 100 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[5][0] != "runtime" || m.keys[5][1] != "heap_objects" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[5] <= 200 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[6][0] != "runtime" || m.keys[6][1] != "total_gc_pause_ns" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[6] <= 100000 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[7][0] != "runtime" || m.keys[7][1] != "total_gc_runs" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[7] <= 1 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+
+	if m.keys[8][0] != "runtime" || m.keys[8][1] != "gc_pause_ns" {
+		t.Fatalf("bad key %v", m.keys)
+	}
+	if m.vals[8] <= 1000 {
+		t.Fatalf("bad val: %v", m.vals)
+	}
+}
+
+func TestInsert(t *testing.T) {
+	k := []string{"hi", "bob"}
+	exp := []string{"hi", "there", "bob"}
+	out := insert(1, "there", k)
+	if !reflect.DeepEqual(exp, out) {
+		t.Fatalf("bad insert %v %v", exp, out)
+	}
+}

+ 52 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink.go

@@ -0,0 +1,52 @@
+package metrics
+
+// The MetricSink interface is used to transmit metrics information
+// to an external system
+type MetricSink interface {
+	// A Gauge should retain the last value it is set to
+	SetGauge(key []string, val float32)
+
+	// Should emit a Key/Value pair for each call
+	EmitKey(key []string, val float32)
+
+	// Counters should accumulate values
+	IncrCounter(key []string, val float32)
+
+	// Samples are for timing information, where quantiles are used
+	AddSample(key []string, val float32)
+}
+
+// BlackholeSink is used to just blackhole messages
+type BlackholeSink struct{}
+
+func (*BlackholeSink) SetGauge(key []string, val float32)    {}
+func (*BlackholeSink) EmitKey(key []string, val float32)     {}
+func (*BlackholeSink) IncrCounter(key []string, val float32) {}
+func (*BlackholeSink) AddSample(key []string, val float32)   {}
+
+// FanoutSink is used to sink to fanout values to multiple sinks
+type FanoutSink []MetricSink
+
+func (fh FanoutSink) SetGauge(key []string, val float32) {
+	for _, s := range fh {
+		s.SetGauge(key, val)
+	}
+}
+
+func (fh FanoutSink) EmitKey(key []string, val float32) {
+	for _, s := range fh {
+		s.EmitKey(key, val)
+	}
+}
+
+func (fh FanoutSink) IncrCounter(key []string, val float32) {
+	for _, s := range fh {
+		s.IncrCounter(key, val)
+	}
+}
+
+func (fh FanoutSink) AddSample(key []string, val float32) {
+	for _, s := range fh {
+		s.AddSample(key, val)
+	}
+}

+ 120 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/sink_test.go

@@ -0,0 +1,120 @@
+package metrics
+
+import (
+	"reflect"
+	"testing"
+)
+
+type MockSink struct {
+	keys [][]string
+	vals []float32
+}
+
+func (m *MockSink) SetGauge(key []string, val float32) {
+	m.keys = append(m.keys, key)
+	m.vals = append(m.vals, val)
+}
+func (m *MockSink) EmitKey(key []string, val float32) {
+	m.keys = append(m.keys, key)
+	m.vals = append(m.vals, val)
+}
+func (m *MockSink) IncrCounter(key []string, val float32) {
+	m.keys = append(m.keys, key)
+	m.vals = append(m.vals, val)
+}
+func (m *MockSink) AddSample(key []string, val float32) {
+	m.keys = append(m.keys, key)
+	m.vals = append(m.vals, val)
+}
+
+func TestFanoutSink_Gauge(t *testing.T) {
+	m1 := &MockSink{}
+	m2 := &MockSink{}
+	fh := &FanoutSink{m1, m2}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	fh.SetGauge(k, v)
+
+	if !reflect.DeepEqual(m1.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m2.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m1.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+	if !reflect.DeepEqual(m2.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func TestFanoutSink_Key(t *testing.T) {
+	m1 := &MockSink{}
+	m2 := &MockSink{}
+	fh := &FanoutSink{m1, m2}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	fh.EmitKey(k, v)
+
+	if !reflect.DeepEqual(m1.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m2.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m1.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+	if !reflect.DeepEqual(m2.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func TestFanoutSink_Counter(t *testing.T) {
+	m1 := &MockSink{}
+	m2 := &MockSink{}
+	fh := &FanoutSink{m1, m2}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	fh.IncrCounter(k, v)
+
+	if !reflect.DeepEqual(m1.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m2.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m1.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+	if !reflect.DeepEqual(m2.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func TestFanoutSink_Sample(t *testing.T) {
+	m1 := &MockSink{}
+	m2 := &MockSink{}
+	fh := &FanoutSink{m1, m2}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	fh.AddSample(k, v)
+
+	if !reflect.DeepEqual(m1.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m2.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m1.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+	if !reflect.DeepEqual(m2.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}

+ 95 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start.go

@@ -0,0 +1,95 @@
+package metrics
+
+import (
+	"os"
+	"time"
+)
+
+// Config is used to configure metrics settings
+type Config struct {
+	ServiceName          string        // Prefixed with keys to seperate services
+	HostName             string        // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
+	EnableHostname       bool          // Enable prefixing gauge values with hostname
+	EnableRuntimeMetrics bool          // Enables profiling of runtime metrics (GC, Goroutines, Memory)
+	EnableTypePrefix     bool          // Prefixes key with a type ("counter", "gauge", "timer")
+	TimerGranularity     time.Duration // Granularity of timers.
+	ProfileInterval      time.Duration // Interval to profile runtime metrics
+}
+
+// Metrics represents an instance of a metrics sink that can
+// be used to emit
+type Metrics struct {
+	Config
+	lastNumGC uint32
+	sink      MetricSink
+}
+
+// Shared global metrics instance
+var globalMetrics *Metrics
+
+func init() {
+	// Initialize to a blackhole sink to avoid errors
+	globalMetrics = &Metrics{sink: &BlackholeSink{}}
+}
+
+// DefaultConfig provides a sane default configuration
+func DefaultConfig(serviceName string) *Config {
+	c := &Config{
+		ServiceName:          serviceName, // Use client provided service
+		HostName:             "",
+		EnableHostname:       true,             // Enable hostname prefix
+		EnableRuntimeMetrics: true,             // Enable runtime profiling
+		EnableTypePrefix:     false,            // Disable type prefix
+		TimerGranularity:     time.Millisecond, // Timers are in milliseconds
+		ProfileInterval:      time.Second,      // Poll runtime every second
+	}
+
+	// Try to get the hostname
+	name, _ := os.Hostname()
+	c.HostName = name
+	return c
+}
+
+// New is used to create a new instance of Metrics
+func New(conf *Config, sink MetricSink) (*Metrics, error) {
+	met := &Metrics{}
+	met.Config = *conf
+	met.sink = sink
+
+	// Start the runtime collector
+	if conf.EnableRuntimeMetrics {
+		go met.collectStats()
+	}
+	return met, nil
+}
+
+// NewGlobal is the same as New, but it assigns the metrics object to be
+// used globally as well as returning it.
+func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
+	metrics, err := New(conf, sink)
+	if err == nil {
+		globalMetrics = metrics
+	}
+	return metrics, err
+}
+
+// Proxy all the methods to the globalMetrics instance
+func SetGauge(key []string, val float32) {
+	globalMetrics.SetGauge(key, val)
+}
+
+func EmitKey(key []string, val float32) {
+	globalMetrics.EmitKey(key, val)
+}
+
+func IncrCounter(key []string, val float32) {
+	globalMetrics.IncrCounter(key, val)
+}
+
+func AddSample(key []string, val float32) {
+	globalMetrics.AddSample(key, val)
+}
+
+func MeasureSince(key []string, start time.Time) {
+	globalMetrics.MeasureSince(key, start)
+}

+ 110 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/start_test.go

@@ -0,0 +1,110 @@
+package metrics
+
+import (
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestDefaultConfig(t *testing.T) {
+	conf := DefaultConfig("service")
+	if conf.ServiceName != "service" {
+		t.Fatalf("Bad name")
+	}
+	if conf.HostName == "" {
+		t.Fatalf("missing hostname")
+	}
+	if !conf.EnableHostname || !conf.EnableRuntimeMetrics {
+		t.Fatalf("expect true")
+	}
+	if conf.EnableTypePrefix {
+		t.Fatalf("expect false")
+	}
+	if conf.TimerGranularity != time.Millisecond {
+		t.Fatalf("bad granularity")
+	}
+	if conf.ProfileInterval != time.Second {
+		t.Fatalf("bad interval")
+	}
+}
+
+func Test_GlobalMetrics_SetGauge(t *testing.T) {
+	m := &MockSink{}
+	globalMetrics = &Metrics{sink: m}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	SetGauge(k, v)
+
+	if !reflect.DeepEqual(m.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func Test_GlobalMetrics_EmitKey(t *testing.T) {
+	m := &MockSink{}
+	globalMetrics = &Metrics{sink: m}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	EmitKey(k, v)
+
+	if !reflect.DeepEqual(m.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func Test_GlobalMetrics_IncrCounter(t *testing.T) {
+	m := &MockSink{}
+	globalMetrics = &Metrics{sink: m}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	IncrCounter(k, v)
+
+	if !reflect.DeepEqual(m.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func Test_GlobalMetrics_AddSample(t *testing.T) {
+	m := &MockSink{}
+	globalMetrics = &Metrics{sink: m}
+
+	k := []string{"test"}
+	v := float32(42.0)
+	AddSample(k, v)
+
+	if !reflect.DeepEqual(m.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if !reflect.DeepEqual(m.vals[0], v) {
+		t.Fatalf("val not equal")
+	}
+}
+
+func Test_GlobalMetrics_MeasureSince(t *testing.T) {
+	m := &MockSink{}
+	globalMetrics = &Metrics{sink: m}
+	globalMetrics.TimerGranularity = time.Millisecond
+
+	k := []string{"test"}
+	now := time.Now()
+	MeasureSince(k, now)
+
+	if !reflect.DeepEqual(m.keys[0], k) {
+		t.Fatalf("key not equal")
+	}
+	if m.vals[0] > 0.1 {
+		t.Fatalf("val too large %v", m.vals[0])
+	}
+}

+ 154 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd.go

@@ -0,0 +1,154 @@
+package metrics
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"net"
+	"strings"
+	"time"
+)
+
+const (
+	// statsdMaxLen is the maximum size of a packet
+	// to send to statsd
+	statsdMaxLen = 1400
+)
+
+// StatsdSink provides a MetricSink that can be used
+// with a statsite or statsd metrics server. It uses
+// only UDP packets, while StatsiteSink uses TCP.
+type StatsdSink struct {
+	addr        string
+	metricQueue chan string
+}
+
+// NewStatsdSink is used to create a new StatsdSink
+func NewStatsdSink(addr string) (*StatsdSink, error) {
+	s := &StatsdSink{
+		addr:        addr,
+		metricQueue: make(chan string, 4096),
+	}
+	go s.flushMetrics()
+	return s, nil
+}
+
+// Close is used to stop flushing to statsd
+func (s *StatsdSink) Shutdown() {
+	close(s.metricQueue)
+}
+
+func (s *StatsdSink) SetGauge(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsdSink) EmitKey(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsdSink) IncrCounter(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsdSink) AddSample(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsdSink) flattenKey(parts []string) string {
+	joined := strings.Join(parts, ".")
+	return strings.Map(func(r rune) rune {
+		switch r {
+		case ':':
+			fallthrough
+		case ' ':
+			return '_'
+		default:
+			return r
+		}
+	}, joined)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsdSink) pushMetric(m string) {
+	select {
+	case s.metricQueue <- m:
+	default:
+	}
+}
+
+// Flushes metrics
+func (s *StatsdSink) flushMetrics() {
+	var sock net.Conn
+	var err error
+	var wait <-chan time.Time
+	ticker := time.NewTicker(flushInterval)
+	defer ticker.Stop()
+
+CONNECT:
+	// Create a buffer
+	buf := bytes.NewBuffer(nil)
+
+	// Attempt to connect
+	sock, err = net.Dial("udp", s.addr)
+	if err != nil {
+		log.Printf("[ERR] Error connecting to statsd! Err: %s", err)
+		goto WAIT
+	}
+
+	for {
+		select {
+		case metric, ok := <-s.metricQueue:
+			// Get a metric from the queue
+			if !ok {
+				goto QUIT
+			}
+
+			// Check if this would overflow the packet size
+			if len(metric)+buf.Len() > statsdMaxLen {
+				_, err := sock.Write(buf.Bytes())
+				buf.Reset()
+				if err != nil {
+					log.Printf("[ERR] Error writing to statsd! Err: %s", err)
+					goto WAIT
+				}
+			}
+
+			// Append to the buffer
+			buf.WriteString(metric)
+
+		case <-ticker.C:
+			if buf.Len() == 0 {
+				continue
+			}
+
+			_, err := sock.Write(buf.Bytes())
+			buf.Reset()
+			if err != nil {
+				log.Printf("[ERR] Error flushing to statsd! Err: %s", err)
+				goto WAIT
+			}
+		}
+	}
+
+WAIT:
+	// Wait for a while
+	wait = time.After(time.Duration(5) * time.Second)
+	for {
+		select {
+		// Dequeue the messages to avoid backlog
+		case _, ok := <-s.metricQueue:
+			if !ok {
+				goto QUIT
+			}
+		case <-wait:
+			goto CONNECT
+		}
+	}
+QUIT:
+	s.metricQueue = nil
+}

+ 105 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsd_test.go

@@ -0,0 +1,105 @@
+package metrics
+
+import (
+	"bufio"
+	"bytes"
+	"net"
+	"testing"
+	"time"
+)
+
+func TestStatsd_Flatten(t *testing.T) {
+	s := &StatsdSink{}
+	flat := s.flattenKey([]string{"a", "b", "c", "d"})
+	if flat != "a.b.c.d" {
+		t.Fatalf("Bad flat")
+	}
+}
+
+func TestStatsd_PushFullQueue(t *testing.T) {
+	q := make(chan string, 1)
+	q <- "full"
+
+	s := &StatsdSink{metricQueue: q}
+	s.pushMetric("omit")
+
+	out := <-q
+	if out != "full" {
+		t.Fatalf("bad val %v", out)
+	}
+
+	select {
+	case v := <-q:
+		t.Fatalf("bad val %v", v)
+	default:
+	}
+}
+
+func TestStatsd_Conn(t *testing.T) {
+	addr := "127.0.0.1:7524"
+	done := make(chan bool)
+	go func() {
+		list, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 7524})
+		if err != nil {
+			panic(err)
+		}
+		defer list.Close()
+		buf := make([]byte, 1500)
+		n, err := list.Read(buf)
+		if err != nil {
+			panic(err)
+		}
+		buf = buf[:n]
+		reader := bufio.NewReader(bytes.NewReader(buf))
+
+		line, err := reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "gauge.val:1.000000|g\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "key.other:2.000000|kv\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "counter.me:3.000000|c\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "sample.slow_thingy:4.000000|ms\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		done <- true
+	}()
+	s, err := NewStatsdSink(addr)
+	if err != nil {
+		t.Fatalf("bad error")
+	}
+
+	s.SetGauge([]string{"gauge", "val"}, float32(1))
+	s.EmitKey([]string{"key", "other"}, float32(2))
+	s.IncrCounter([]string{"counter", "me"}, float32(3))
+	s.AddSample([]string{"sample", "slow thingy"}, float32(4))
+
+	select {
+	case <-done:
+		s.Shutdown()
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timeout")
+	}
+}

+ 142 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite.go

@@ -0,0 +1,142 @@
+package metrics
+
+import (
+	"bufio"
+	"fmt"
+	"log"
+	"net"
+	"strings"
+	"time"
+)
+
+const (
+	// We force flush the statsite metrics after this period of
+	// inactivity. Prevents stats from getting stuck in a buffer
+	// forever.
+	flushInterval = 100 * time.Millisecond
+)
+
+// StatsiteSink provides a MetricSink that can be used with a
+// statsite metrics server
+type StatsiteSink struct {
+	addr        string
+	metricQueue chan string
+}
+
+// NewStatsiteSink is used to create a new StatsiteSink
+func NewStatsiteSink(addr string) (*StatsiteSink, error) {
+	s := &StatsiteSink{
+		addr:        addr,
+		metricQueue: make(chan string, 4096),
+	}
+	go s.flushMetrics()
+	return s, nil
+}
+
+// Close is used to stop flushing to statsite
+func (s *StatsiteSink) Shutdown() {
+	close(s.metricQueue)
+}
+
+func (s *StatsiteSink) SetGauge(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|g\n", flatKey, val))
+}
+
+func (s *StatsiteSink) EmitKey(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|kv\n", flatKey, val))
+}
+
+func (s *StatsiteSink) IncrCounter(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|c\n", flatKey, val))
+}
+
+func (s *StatsiteSink) AddSample(key []string, val float32) {
+	flatKey := s.flattenKey(key)
+	s.pushMetric(fmt.Sprintf("%s:%f|ms\n", flatKey, val))
+}
+
+// Flattens the key for formatting, removes spaces
+func (s *StatsiteSink) flattenKey(parts []string) string {
+	joined := strings.Join(parts, ".")
+	return strings.Map(func(r rune) rune {
+		switch r {
+		case ':':
+			fallthrough
+		case ' ':
+			return '_'
+		default:
+			return r
+		}
+	}, joined)
+}
+
+// Does a non-blocking push to the metrics queue
+func (s *StatsiteSink) pushMetric(m string) {
+	select {
+	case s.metricQueue <- m:
+	default:
+	}
+}
+
+// Flushes metrics
+func (s *StatsiteSink) flushMetrics() {
+	var sock net.Conn
+	var err error
+	var wait <-chan time.Time
+	var buffered *bufio.Writer
+	ticker := time.NewTicker(flushInterval)
+	defer ticker.Stop()
+
+CONNECT:
+	// Attempt to connect
+	sock, err = net.Dial("tcp", s.addr)
+	if err != nil {
+		log.Printf("[ERR] Error connecting to statsite! Err: %s", err)
+		goto WAIT
+	}
+
+	// Create a buffered writer
+	buffered = bufio.NewWriter(sock)
+
+	for {
+		select {
+		case metric, ok := <-s.metricQueue:
+			// Get a metric from the queue
+			if !ok {
+				goto QUIT
+			}
+
+			// Try to send to statsite
+			_, err := buffered.Write([]byte(metric))
+			if err != nil {
+				log.Printf("[ERR] Error writing to statsite! Err: %s", err)
+				goto WAIT
+			}
+		case <-ticker.C:
+			if err := buffered.Flush(); err != nil {
+				log.Printf("[ERR] Error flushing to statsite! Err: %s", err)
+				goto WAIT
+			}
+		}
+	}
+
+WAIT:
+	// Wait for a while
+	wait = time.After(time.Duration(5) * time.Second)
+	for {
+		select {
+		// Dequeue the messages to avoid backlog
+		case _, ok := <-s.metricQueue:
+			if !ok {
+				goto QUIT
+			}
+		case <-wait:
+			goto CONNECT
+		}
+	}
+QUIT:
+	s.metricQueue = nil
+}

+ 101 - 0
libnetwork/Godeps/_workspace/src/github.com/armon/go-metrics/statsite_test.go

@@ -0,0 +1,101 @@
+package metrics
+
+import (
+	"bufio"
+	"net"
+	"testing"
+	"time"
+)
+
+func acceptConn(addr string) net.Conn {
+	ln, _ := net.Listen("tcp", addr)
+	conn, _ := ln.Accept()
+	return conn
+}
+
+func TestStatsite_Flatten(t *testing.T) {
+	s := &StatsiteSink{}
+	flat := s.flattenKey([]string{"a", "b", "c", "d"})
+	if flat != "a.b.c.d" {
+		t.Fatalf("Bad flat")
+	}
+}
+
+func TestStatsite_PushFullQueue(t *testing.T) {
+	q := make(chan string, 1)
+	q <- "full"
+
+	s := &StatsiteSink{metricQueue: q}
+	s.pushMetric("omit")
+
+	out := <-q
+	if out != "full" {
+		t.Fatalf("bad val %v", out)
+	}
+
+	select {
+	case v := <-q:
+		t.Fatalf("bad val %v", v)
+	default:
+	}
+}
+
+func TestStatsite_Conn(t *testing.T) {
+	addr := "localhost:7523"
+	done := make(chan bool)
+	go func() {
+		conn := acceptConn(addr)
+		reader := bufio.NewReader(conn)
+
+		line, err := reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "gauge.val:1.000000|g\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "key.other:2.000000|kv\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "counter.me:3.000000|c\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		line, err = reader.ReadString('\n')
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		if line != "sample.slow_thingy:4.000000|ms\n" {
+			t.Fatalf("bad line %s", line)
+		}
+
+		conn.Close()
+		done <- true
+	}()
+	s, err := NewStatsiteSink(addr)
+	if err != nil {
+		t.Fatalf("bad error")
+	}
+
+	s.SetGauge([]string{"gauge", "val"}, float32(1))
+	s.EmitKey([]string{"key", "other"}, float32(2))
+	s.IncrCounter([]string{"counter", "me"}, float32(3))
+	s.AddSample([]string{"sample", "slow thingy"}, float32(4))
+
+	select {
+	case <-done:
+		s.Shutdown()
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timeout")
+	}
+}

+ 143 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/0doc.go

@@ -0,0 +1,143 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+/*
+High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc .
+
+Supported Serialization formats are:
+
+  - msgpack: [https://github.com/msgpack/msgpack]
+  - binc: [http://github.com/ugorji/binc]
+
+To install:
+
+    go get github.com/ugorji/go/codec
+
+The idiomatic Go support is as seen in other encoding packages in
+the standard library (ie json, xml, gob, etc).
+
+Rich Feature Set includes:
+
+  - Simple but extremely powerful and feature-rich API
+  - Very High Performance.
+    Our extensive benchmarks show us outperforming Gob, Json and Bson by 2-4X.
+    This was achieved by taking extreme care on:
+      - managing allocation
+      - function frame size (important due to Go's use of split stacks),
+      - reflection use (and by-passing reflection for common types)
+      - recursion implications
+      - zero-copy mode (encoding/decoding to byte slice without using temp buffers)
+  - Correct.
+    Care was taken to precisely handle corner cases like:
+      overflows, nil maps and slices, nil value in stream, etc.
+  - Efficient zero-copying into temporary byte buffers
+    when encoding into or decoding from a byte slice.
+  - Standard field renaming via tags
+  - Encoding from any value
+    (struct, slice, map, primitives, pointers, interface{}, etc)
+  - Decoding into pointer to any non-nil typed value
+    (struct, slice, map, int, float32, bool, string, reflect.Value, etc)
+  - Supports extension functions to handle the encode/decode of custom types
+  - Support Go 1.2 encoding.BinaryMarshaler/BinaryUnmarshaler
+  - Schema-less decoding
+    (decode into a pointer to a nil interface{} as opposed to a typed non-nil value).
+    Includes Options to configure what specific map or slice type to use
+    when decoding an encoded list or map into a nil interface{}
+  - Provides a RPC Server and Client Codec for net/rpc communication protocol.
+  - Msgpack Specific:
+      - Provides extension functions to handle spec-defined extensions (binary, timestamp)
+      - Options to resolve ambiguities in handling raw bytes (as string or []byte)
+        during schema-less decoding (decoding into a nil interface{})
+      - RPC Server/Client Codec for msgpack-rpc protocol defined at:
+        https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
+  - Fast Paths for some container types:
+    For some container types, we circumvent reflection and its associated overhead
+    and allocation costs, and encode/decode directly. These types are:
+	    []interface{}
+	    []int
+	    []string
+	    map[interface{}]interface{}
+	    map[int]interface{}
+	    map[string]interface{}
+
+Extension Support
+
+Users can register a function to handle the encoding or decoding of
+their custom types.
+
+There are no restrictions on what the custom type can be. Some examples:
+
+    type BisSet   []int
+    type BitSet64 uint64
+    type UUID     string
+    type MyStructWithUnexportedFields struct { a int; b bool; c []int; }
+    type GifImage struct { ... }
+
+As an illustration, MyStructWithUnexportedFields would normally be
+encoded as an empty map because it has no exported fields, while UUID
+would be encoded as a string. However, with extension support, you can
+encode any of these however you like.
+
+RPC
+
+RPC Client and Server Codecs are implemented, so the codecs can be used
+with the standard net/rpc package.
+
+Usage
+
+Typical usage model:
+
+    // create and configure Handle
+    var (
+      bh codec.BincHandle
+      mh codec.MsgpackHandle
+    )
+
+    mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
+
+    // configure extensions
+    // e.g. for msgpack, define functions and enable Time support for tag 1
+    // mh.AddExt(reflect.TypeOf(time.Time{}), 1, myMsgpackTimeEncodeExtFn, myMsgpackTimeDecodeExtFn)
+
+    // create and use decoder/encoder
+    var (
+      r io.Reader
+      w io.Writer
+      b []byte
+      h = &bh // or mh to use msgpack
+    )
+
+    dec = codec.NewDecoder(r, h)
+    dec = codec.NewDecoderBytes(b, h)
+    err = dec.Decode(&v)
+
+    enc = codec.NewEncoder(w, h)
+    enc = codec.NewEncoderBytes(&b, h)
+    err = enc.Encode(v)
+
+    //RPC Server
+    go func() {
+        for {
+            conn, err := listener.Accept()
+            rpcCodec := codec.GoRpc.ServerCodec(conn, h)
+            //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h)
+            rpc.ServeCodec(rpcCodec)
+        }
+    }()
+
+    //RPC Communication (client side)
+    conn, err = net.Dial("tcp", "localhost:5555")
+    rpcCodec := codec.GoRpc.ClientCodec(conn, h)
+    //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
+    client := rpc.NewClientWithCodec(rpcCodec)
+
+Representative Benchmark Results
+
+Run the benchmark suite using:
+   go test -bi -bench=. -benchmem
+
+To run full benchmark suite (including against vmsgpack and bson),
+see notes in ext_dep_test.go
+
+*/
+package codec

+ 174 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/README.md

@@ -0,0 +1,174 @@
+# Codec
+
+High Performance and Feature-Rich Idiomatic Go Library providing
+encode/decode support for different serialization formats.
+
+Supported Serialization formats are:
+
+  - msgpack: [https://github.com/msgpack/msgpack]
+  - binc: [http://github.com/ugorji/binc]
+
+To install:
+
+    go get github.com/ugorji/go/codec
+
+Online documentation: [http://godoc.org/github.com/ugorji/go/codec]
+
+The idiomatic Go support is as seen in other encoding packages in
+the standard library (ie json, xml, gob, etc).
+
+Rich Feature Set includes:
+
+  - Simple but extremely powerful and feature-rich API
+  - Very High Performance.   
+    Our extensive benchmarks show us outperforming Gob, Json and Bson by 2-4X.
+    This was achieved by taking extreme care on:
+      - managing allocation
+      - function frame size (important due to Go's use of split stacks),
+      - reflection use (and by-passing reflection for common types)
+      - recursion implications
+      - zero-copy mode (encoding/decoding to byte slice without using temp buffers)
+  - Correct.  
+    Care was taken to precisely handle corner cases like: 
+      overflows, nil maps and slices, nil value in stream, etc.
+  - Efficient zero-copying into temporary byte buffers  
+    when encoding into or decoding from a byte slice.
+  - Standard field renaming via tags
+  - Encoding from any value  
+    (struct, slice, map, primitives, pointers, interface{}, etc)
+  - Decoding into pointer to any non-nil typed value  
+    (struct, slice, map, int, float32, bool, string, reflect.Value, etc)
+  - Supports extension functions to handle the encode/decode of custom types
+  - Support Go 1.2 encoding.BinaryMarshaler/BinaryUnmarshaler
+  - Schema-less decoding  
+    (decode into a pointer to a nil interface{} as opposed to a typed non-nil value).  
+    Includes Options to configure what specific map or slice type to use 
+    when decoding an encoded list or map into a nil interface{}
+  - Provides a RPC Server and Client Codec for net/rpc communication protocol.
+  - Msgpack Specific:
+      - Provides extension functions to handle spec-defined extensions (binary, timestamp)
+      - Options to resolve ambiguities in handling raw bytes (as string or []byte)  
+        during schema-less decoding (decoding into a nil interface{})
+      - RPC Server/Client Codec for msgpack-rpc protocol defined at: 
+        https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
+  - Fast Paths for some container types:  
+    For some container types, we circumvent reflection and its associated overhead
+    and allocation costs, and encode/decode directly. These types are:  
+	    []interface{}
+	    []int
+	    []string
+	    map[interface{}]interface{}
+	    map[int]interface{}
+	    map[string]interface{}
+
+## Extension Support
+
+Users can register a function to handle the encoding or decoding of
+their custom types.
+
+There are no restrictions on what the custom type can be. Some examples:
+
+    type BisSet   []int
+    type BitSet64 uint64
+    type UUID     string
+    type MyStructWithUnexportedFields struct { a int; b bool; c []int; }
+    type GifImage struct { ... }
+
+As an illustration, MyStructWithUnexportedFields would normally be
+encoded as an empty map because it has no exported fields, while UUID
+would be encoded as a string. However, with extension support, you can
+encode any of these however you like.
+
+## RPC
+
+RPC Client and Server Codecs are implemented, so the codecs can be used
+with the standard net/rpc package.
+
+## Usage
+
+Typical usage model:
+
+    // create and configure Handle
+    var (
+      bh codec.BincHandle
+      mh codec.MsgpackHandle
+    )
+
+    mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
+    
+    // configure extensions
+    // e.g. for msgpack, define functions and enable Time support for tag 1
+    // mh.AddExt(reflect.TypeOf(time.Time{}), 1, myMsgpackTimeEncodeExtFn, myMsgpackTimeDecodeExtFn)
+
+    // create and use decoder/encoder
+    var (
+      r io.Reader
+      w io.Writer
+      b []byte
+      h = &bh // or mh to use msgpack
+    )
+    
+    dec = codec.NewDecoder(r, h)
+    dec = codec.NewDecoderBytes(b, h)
+    err = dec.Decode(&v) 
+    
+    enc = codec.NewEncoder(w, h)
+    enc = codec.NewEncoderBytes(&b, h)
+    err = enc.Encode(v)
+    
+    //RPC Server
+    go func() {
+        for {
+            conn, err := listener.Accept()
+            rpcCodec := codec.GoRpc.ServerCodec(conn, h)
+            //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h)
+            rpc.ServeCodec(rpcCodec)
+        }
+    }()
+
+    //RPC Communication (client side)
+    conn, err = net.Dial("tcp", "localhost:5555")
+    rpcCodec := codec.GoRpc.ClientCodec(conn, h)
+    //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
+    client := rpc.NewClientWithCodec(rpcCodec)
+
+## Representative Benchmark Results
+
+A sample run of benchmark using "go test -bi -bench=. -benchmem":
+
+    /proc/cpuinfo: Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz (HT)
+    
+    ..............................................
+    BENCHMARK INIT: 2013-10-16 11:02:50.345970786 -0400 EDT
+    To run full benchmark comparing encodings (MsgPack, Binc, JSON, GOB, etc), use: "go test -bench=."
+    Benchmark: 
+    	Struct recursive Depth:             1
+    	ApproxDeepSize Of benchmark Struct: 4694 bytes
+    Benchmark One-Pass Run:
+    	 v-msgpack: len: 1600 bytes
+    	      bson: len: 3025 bytes
+    	   msgpack: len: 1560 bytes
+    	      binc: len: 1187 bytes
+    	       gob: len: 1972 bytes
+    	      json: len: 2538 bytes
+    ..............................................
+    PASS
+    Benchmark__Msgpack____Encode	   50000	     54359 ns/op	   14953 B/op	      83 allocs/op
+    Benchmark__Msgpack____Decode	   10000	    106531 ns/op	   14990 B/op	     410 allocs/op
+    Benchmark__Binc_NoSym_Encode	   50000	     53956 ns/op	   14966 B/op	      83 allocs/op
+    Benchmark__Binc_NoSym_Decode	   10000	    103751 ns/op	   14529 B/op	     386 allocs/op
+    Benchmark__Binc_Sym___Encode	   50000	     65961 ns/op	   17130 B/op	      88 allocs/op
+    Benchmark__Binc_Sym___Decode	   10000	    106310 ns/op	   15857 B/op	     287 allocs/op
+    Benchmark__Gob________Encode	   10000	    135944 ns/op	   21189 B/op	     237 allocs/op
+    Benchmark__Gob________Decode	    5000	    405390 ns/op	   83460 B/op	    1841 allocs/op
+    Benchmark__Json_______Encode	   20000	     79412 ns/op	   13874 B/op	     102 allocs/op
+    Benchmark__Json_______Decode	   10000	    247979 ns/op	   14202 B/op	     493 allocs/op
+    Benchmark__Bson_______Encode	   10000	    121762 ns/op	   27814 B/op	     514 allocs/op
+    Benchmark__Bson_______Decode	   10000	    162126 ns/op	   16514 B/op	     789 allocs/op
+    Benchmark__VMsgpack___Encode	   50000	     69155 ns/op	   12370 B/op	     344 allocs/op
+    Benchmark__VMsgpack___Decode	   10000	    151609 ns/op	   20307 B/op	     571 allocs/op
+    ok  	ugorji.net/codec	30.827s
+
+To run full benchmark suite (including against vmsgpack and bson), 
+see notes in ext\_dep\_test.go
+

+ 319 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/bench_test.go

@@ -0,0 +1,319 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"reflect"
+	"runtime"
+	"testing"
+	"time"
+)
+
+// Sample way to run:
+// go test -bi -bv -bd=1 -benchmem -bench=.
+
+var (
+	_       = fmt.Printf
+	benchTs *TestStruc
+
+	approxSize int
+
+	benchDoInitBench     bool
+	benchVerify          bool
+	benchUnscientificRes bool = false
+	//depth of 0 maps to ~400bytes json-encoded string, 1 maps to ~1400 bytes, etc
+	//For depth>1, we likely trigger stack growth for encoders, making benchmarking unreliable.
+	benchDepth     int
+	benchInitDebug bool
+	benchCheckers  []benchChecker
+)
+
+type benchEncFn func(interface{}) ([]byte, error)
+type benchDecFn func([]byte, interface{}) error
+type benchIntfFn func() interface{}
+
+type benchChecker struct {
+	name     string
+	encodefn benchEncFn
+	decodefn benchDecFn
+}
+
+func benchInitFlags() {
+	flag.BoolVar(&benchInitDebug, "bg", false, "Bench Debug")
+	flag.IntVar(&benchDepth, "bd", 1, "Bench Depth: If >1, potential unreliable results due to stack growth")
+	flag.BoolVar(&benchDoInitBench, "bi", false, "Run Bench Init")
+	flag.BoolVar(&benchVerify, "bv", false, "Verify Decoded Value during Benchmark")
+	flag.BoolVar(&benchUnscientificRes, "bu", false, "Show Unscientific Results during Benchmark")
+}
+
+func benchInit() {
+	benchTs = newTestStruc(benchDepth, true)
+	approxSize = approxDataSize(reflect.ValueOf(benchTs))
+	bytesLen := 1024 * 4 * (benchDepth + 1) * (benchDepth + 1)
+	if bytesLen < approxSize {
+		bytesLen = approxSize
+	}
+
+	benchCheckers = append(benchCheckers,
+		benchChecker{"msgpack", fnMsgpackEncodeFn, fnMsgpackDecodeFn},
+		benchChecker{"binc-nosym", fnBincNoSymEncodeFn, fnBincNoSymDecodeFn},
+		benchChecker{"binc-sym", fnBincSymEncodeFn, fnBincSymDecodeFn},
+		benchChecker{"simple", fnSimpleEncodeFn, fnSimpleDecodeFn},
+		benchChecker{"gob", fnGobEncodeFn, fnGobDecodeFn},
+		benchChecker{"json", fnJsonEncodeFn, fnJsonDecodeFn},
+	)
+	if benchDoInitBench {
+		runBenchInit()
+	}
+}
+
+func runBenchInit() {
+	logT(nil, "..............................................")
+	logT(nil, "BENCHMARK INIT: %v", time.Now())
+	logT(nil, "To run full benchmark comparing encodings (MsgPack, Binc, Simple, JSON, GOB, etc), "+
+		"use: \"go test -bench=.\"")
+	logT(nil, "Benchmark: ")
+	logT(nil, "\tStruct recursive Depth:             %d", benchDepth)
+	if approxSize > 0 {
+		logT(nil, "\tApproxDeepSize Of benchmark Struct: %d bytes", approxSize)
+	}
+	if benchUnscientificRes {
+		logT(nil, "Benchmark One-Pass Run (with Unscientific Encode/Decode times): ")
+	} else {
+		logT(nil, "Benchmark One-Pass Run:")
+	}
+	for _, bc := range benchCheckers {
+		doBenchCheck(bc.name, bc.encodefn, bc.decodefn)
+	}
+	logT(nil, "..............................................")
+	if benchInitDebug {
+		logT(nil, "<<<<====>>>> depth: %v, ts: %#v\n", benchDepth, benchTs)
+	}
+}
+
+func fnBenchNewTs() interface{} {
+	return new(TestStruc)
+}
+
+func doBenchCheck(name string, encfn benchEncFn, decfn benchDecFn) {
+	runtime.GC()
+	tnow := time.Now()
+	buf, err := encfn(benchTs)
+	if err != nil {
+		logT(nil, "\t%10s: **** Error encoding benchTs: %v", name, err)
+	}
+	encDur := time.Now().Sub(tnow)
+	encLen := len(buf)
+	runtime.GC()
+	if !benchUnscientificRes {
+		logT(nil, "\t%10s: len: %d bytes\n", name, encLen)
+		return
+	}
+	tnow = time.Now()
+	if err = decfn(buf, new(TestStruc)); err != nil {
+		logT(nil, "\t%10s: **** Error decoding into new TestStruc: %v", name, err)
+	}
+	decDur := time.Now().Sub(tnow)
+	logT(nil, "\t%10s: len: %d bytes, encode: %v, decode: %v\n", name, encLen, encDur, decDur)
+}
+
+func fnBenchmarkEncode(b *testing.B, encName string, ts interface{}, encfn benchEncFn) {
+	runtime.GC()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := encfn(ts)
+		if err != nil {
+			logT(b, "Error encoding benchTs: %s: %v", encName, err)
+			b.FailNow()
+		}
+	}
+}
+
+func fnBenchmarkDecode(b *testing.B, encName string, ts interface{},
+	encfn benchEncFn, decfn benchDecFn, newfn benchIntfFn,
+) {
+	buf, err := encfn(ts)
+	if err != nil {
+		logT(b, "Error encoding benchTs: %s: %v", encName, err)
+		b.FailNow()
+	}
+	runtime.GC()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		ts = newfn()
+		if err = decfn(buf, ts); err != nil {
+			logT(b, "Error decoding into new TestStruc: %s: %v", encName, err)
+			b.FailNow()
+		}
+		if benchVerify {
+			if vts, vok := ts.(*TestStruc); vok {
+				verifyTsTree(b, vts)
+			}
+		}
+	}
+}
+
+func verifyTsTree(b *testing.B, ts *TestStruc) {
+	var ts0, ts1m, ts2m, ts1s, ts2s *TestStruc
+	ts0 = ts
+
+	if benchDepth > 0 {
+		ts1m, ts1s = verifyCheckAndGet(b, ts0)
+	}
+
+	if benchDepth > 1 {
+		ts2m, ts2s = verifyCheckAndGet(b, ts1m)
+	}
+	for _, tsx := range []*TestStruc{ts0, ts1m, ts2m, ts1s, ts2s} {
+		if tsx != nil {
+			verifyOneOne(b, tsx)
+		}
+	}
+}
+
+func verifyCheckAndGet(b *testing.B, ts0 *TestStruc) (ts1m *TestStruc, ts1s *TestStruc) {
+	// if len(ts1m.Ms) <= 2 {
+	// 	logT(b, "Error: ts1m.Ms len should be > 2. Got: %v", len(ts1m.Ms))
+	// 	b.FailNow()
+	// }
+	if len(ts0.Its) == 0 {
+		logT(b, "Error: ts0.Islice len should be > 0. Got: %v", len(ts0.Its))
+		b.FailNow()
+	}
+	ts1m = ts0.Mtsptr["0"]
+	ts1s = ts0.Its[0]
+	if ts1m == nil || ts1s == nil {
+		logT(b, "Error: At benchDepth 1, No *TestStruc found")
+		b.FailNow()
+	}
+	return
+}
+
+func verifyOneOne(b *testing.B, ts *TestStruc) {
+	if ts.I64slice[2] != int64(3) {
+		logT(b, "Error: Decode failed by checking values")
+		b.FailNow()
+	}
+}
+
+func fnMsgpackEncodeFn(ts interface{}) (bs []byte, err error) {
+	err = NewEncoderBytes(&bs, testMsgpackH).Encode(ts)
+	return
+}
+
+func fnMsgpackDecodeFn(buf []byte, ts interface{}) error {
+	return NewDecoderBytes(buf, testMsgpackH).Decode(ts)
+}
+
+func fnBincEncodeFn(ts interface{}, sym AsSymbolFlag) (bs []byte, err error) {
+	tSym := testBincH.AsSymbols
+	testBincH.AsSymbols = sym
+	err = NewEncoderBytes(&bs, testBincH).Encode(ts)
+	testBincH.AsSymbols = tSym
+	return
+}
+
+func fnBincDecodeFn(buf []byte, ts interface{}, sym AsSymbolFlag) (err error) {
+	tSym := testBincH.AsSymbols
+	testBincH.AsSymbols = sym
+	err = NewDecoderBytes(buf, testBincH).Decode(ts)
+	testBincH.AsSymbols = tSym
+	return
+}
+
+func fnBincNoSymEncodeFn(ts interface{}) (bs []byte, err error) {
+	return fnBincEncodeFn(ts, AsSymbolNone)
+}
+
+func fnBincNoSymDecodeFn(buf []byte, ts interface{}) error {
+	return fnBincDecodeFn(buf, ts, AsSymbolNone)
+}
+
+func fnBincSymEncodeFn(ts interface{}) (bs []byte, err error) {
+	return fnBincEncodeFn(ts, AsSymbolAll)
+}
+
+func fnBincSymDecodeFn(buf []byte, ts interface{}) error {
+	return fnBincDecodeFn(buf, ts, AsSymbolAll)
+}
+
+func fnSimpleEncodeFn(ts interface{}) (bs []byte, err error) {
+	err = NewEncoderBytes(&bs, testSimpleH).Encode(ts)
+	return
+}
+
+func fnSimpleDecodeFn(buf []byte, ts interface{}) error {
+	return NewDecoderBytes(buf, testSimpleH).Decode(ts)
+}
+
+func fnGobEncodeFn(ts interface{}) ([]byte, error) {
+	bbuf := new(bytes.Buffer)
+	err := gob.NewEncoder(bbuf).Encode(ts)
+	return bbuf.Bytes(), err
+}
+
+func fnGobDecodeFn(buf []byte, ts interface{}) error {
+	return gob.NewDecoder(bytes.NewBuffer(buf)).Decode(ts)
+}
+
+func fnJsonEncodeFn(ts interface{}) ([]byte, error) {
+	return json.Marshal(ts)
+}
+
+func fnJsonDecodeFn(buf []byte, ts interface{}) error {
+	return json.Unmarshal(buf, ts)
+}
+
+func Benchmark__Msgpack____Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "msgpack", benchTs, fnMsgpackEncodeFn)
+}
+
+func Benchmark__Msgpack____Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "msgpack", benchTs, fnMsgpackEncodeFn, fnMsgpackDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__Binc_NoSym_Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "binc", benchTs, fnBincNoSymEncodeFn)
+}
+
+func Benchmark__Binc_NoSym_Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "binc", benchTs, fnBincNoSymEncodeFn, fnBincNoSymDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__Binc_Sym___Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "binc", benchTs, fnBincSymEncodeFn)
+}
+
+func Benchmark__Binc_Sym___Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "binc", benchTs, fnBincSymEncodeFn, fnBincSymDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__Simple____Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "simple", benchTs, fnSimpleEncodeFn)
+}
+
+func Benchmark__Simple____Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "simple", benchTs, fnSimpleEncodeFn, fnSimpleDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__Gob________Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "gob", benchTs, fnGobEncodeFn)
+}
+
+func Benchmark__Gob________Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "gob", benchTs, fnGobEncodeFn, fnGobDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__Json_______Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "json", benchTs, fnJsonEncodeFn)
+}
+
+func Benchmark__Json_______Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "json", benchTs, fnJsonEncodeFn, fnJsonDecodeFn, fnBenchNewTs)
+}

+ 786 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/binc.go

@@ -0,0 +1,786 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"math"
+	// "reflect"
+	// "sync/atomic"
+	"time"
+	//"fmt"
+)
+
+const bincDoPrune = true // No longer needed. Needed before as C lib did not support pruning.
+
+//var _ = fmt.Printf
+
+// vd as low 4 bits (there are 16 slots)
+const (
+	bincVdSpecial byte = iota
+	bincVdPosInt
+	bincVdNegInt
+	bincVdFloat
+
+	bincVdString
+	bincVdByteArray
+	bincVdArray
+	bincVdMap
+
+	bincVdTimestamp
+	bincVdSmallInt
+	bincVdUnicodeOther
+	bincVdSymbol
+
+	bincVdDecimal
+	_               // open slot
+	_               // open slot
+	bincVdCustomExt = 0x0f
+)
+
+const (
+	bincSpNil byte = iota
+	bincSpFalse
+	bincSpTrue
+	bincSpNan
+	bincSpPosInf
+	bincSpNegInf
+	bincSpZeroFloat
+	bincSpZero
+	bincSpNegOne
+)
+
+const (
+	bincFlBin16 byte = iota
+	bincFlBin32
+	_ // bincFlBin32e
+	bincFlBin64
+	_ // bincFlBin64e
+	// others not currently supported
+)
+
+type bincEncDriver struct {
+	w encWriter
+	m map[string]uint16 // symbols
+	s uint32            // symbols sequencer
+	b [8]byte
+}
+
+func (e *bincEncDriver) isBuiltinType(rt uintptr) bool {
+	return rt == timeTypId
+}
+
+func (e *bincEncDriver) encodeBuiltin(rt uintptr, v interface{}) {
+	switch rt {
+	case timeTypId:
+		bs := encodeTime(v.(time.Time))
+		e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs)))
+		e.w.writeb(bs)
+	}
+}
+
+func (e *bincEncDriver) encodeNil() {
+	e.w.writen1(bincVdSpecial<<4 | bincSpNil)
+}
+
+func (e *bincEncDriver) encodeBool(b bool) {
+	if b {
+		e.w.writen1(bincVdSpecial<<4 | bincSpTrue)
+	} else {
+		e.w.writen1(bincVdSpecial<<4 | bincSpFalse)
+	}
+}
+
+func (e *bincEncDriver) encodeFloat32(f float32) {
+	if f == 0 {
+		e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat)
+		return
+	}
+	e.w.writen1(bincVdFloat<<4 | bincFlBin32)
+	e.w.writeUint32(math.Float32bits(f))
+}
+
+func (e *bincEncDriver) encodeFloat64(f float64) {
+	if f == 0 {
+		e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat)
+		return
+	}
+	bigen.PutUint64(e.b[:], math.Float64bits(f))
+	if bincDoPrune {
+		i := 7
+		for ; i >= 0 && (e.b[i] == 0); i-- {
+		}
+		i++
+		if i <= 6 {
+			e.w.writen1(bincVdFloat<<4 | 0x8 | bincFlBin64)
+			e.w.writen1(byte(i))
+			e.w.writeb(e.b[:i])
+			return
+		}
+	}
+	e.w.writen1(bincVdFloat<<4 | bincFlBin64)
+	e.w.writeb(e.b[:])
+}
+
+func (e *bincEncDriver) encIntegerPrune(bd byte, pos bool, v uint64, lim uint8) {
+	if lim == 4 {
+		bigen.PutUint32(e.b[:lim], uint32(v))
+	} else {
+		bigen.PutUint64(e.b[:lim], v)
+	}
+	if bincDoPrune {
+		i := pruneSignExt(e.b[:lim], pos)
+		e.w.writen1(bd | lim - 1 - byte(i))
+		e.w.writeb(e.b[i:lim])
+	} else {
+		e.w.writen1(bd | lim - 1)
+		e.w.writeb(e.b[:lim])
+	}
+}
+
+func (e *bincEncDriver) encodeInt(v int64) {
+	const nbd byte = bincVdNegInt << 4
+	switch {
+	case v >= 0:
+		e.encUint(bincVdPosInt<<4, true, uint64(v))
+	case v == -1:
+		e.w.writen1(bincVdSpecial<<4 | bincSpNegOne)
+	default:
+		e.encUint(bincVdNegInt<<4, false, uint64(-v))
+	}
+}
+
+func (e *bincEncDriver) encodeUint(v uint64) {
+	e.encUint(bincVdPosInt<<4, true, v)
+}
+
+func (e *bincEncDriver) encUint(bd byte, pos bool, v uint64) {
+	switch {
+	case v == 0:
+		e.w.writen1(bincVdSpecial<<4 | bincSpZero)
+	case pos && v >= 1 && v <= 16:
+		e.w.writen1(bincVdSmallInt<<4 | byte(v-1))
+	case v <= math.MaxUint8:
+		e.w.writen2(bd|0x0, byte(v))
+	case v <= math.MaxUint16:
+		e.w.writen1(bd | 0x01)
+		e.w.writeUint16(uint16(v))
+	case v <= math.MaxUint32:
+		e.encIntegerPrune(bd, pos, v, 4)
+	default:
+		e.encIntegerPrune(bd, pos, v, 8)
+	}
+}
+
+func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) {
+	e.encLen(bincVdCustomExt<<4, uint64(length))
+	e.w.writen1(xtag)
+}
+
+func (e *bincEncDriver) encodeArrayPreamble(length int) {
+	e.encLen(bincVdArray<<4, uint64(length))
+}
+
+func (e *bincEncDriver) encodeMapPreamble(length int) {
+	e.encLen(bincVdMap<<4, uint64(length))
+}
+
+func (e *bincEncDriver) encodeString(c charEncoding, v string) {
+	l := uint64(len(v))
+	e.encBytesLen(c, l)
+	if l > 0 {
+		e.w.writestr(v)
+	}
+}
+
+func (e *bincEncDriver) encodeSymbol(v string) {
+	// if WriteSymbolsNoRefs {
+	// 	e.encodeString(c_UTF8, v)
+	// 	return
+	// }
+
+	//symbols only offer benefit when string length > 1.
+	//This is because strings with length 1 take only 2 bytes to store
+	//(bd with embedded length, and single byte for string val).
+
+	l := len(v)
+	switch l {
+	case 0:
+		e.encBytesLen(c_UTF8, 0)
+		return
+	case 1:
+		e.encBytesLen(c_UTF8, 1)
+		e.w.writen1(v[0])
+		return
+	}
+	if e.m == nil {
+		e.m = make(map[string]uint16, 16)
+	}
+	ui, ok := e.m[v]
+	if ok {
+		if ui <= math.MaxUint8 {
+			e.w.writen2(bincVdSymbol<<4, byte(ui))
+		} else {
+			e.w.writen1(bincVdSymbol<<4 | 0x8)
+			e.w.writeUint16(ui)
+		}
+	} else {
+		e.s++
+		ui = uint16(e.s)
+		//ui = uint16(atomic.AddUint32(&e.s, 1))
+		e.m[v] = ui
+		var lenprec uint8
+		switch {
+		case l <= math.MaxUint8:
+			// lenprec = 0
+		case l <= math.MaxUint16:
+			lenprec = 1
+		case int64(l) <= math.MaxUint32:
+			lenprec = 2
+		default:
+			lenprec = 3
+		}
+		if ui <= math.MaxUint8 {
+			e.w.writen2(bincVdSymbol<<4|0x0|0x4|lenprec, byte(ui))
+		} else {
+			e.w.writen1(bincVdSymbol<<4 | 0x8 | 0x4 | lenprec)
+			e.w.writeUint16(ui)
+		}
+		switch lenprec {
+		case 0:
+			e.w.writen1(byte(l))
+		case 1:
+			e.w.writeUint16(uint16(l))
+		case 2:
+			e.w.writeUint32(uint32(l))
+		default:
+			e.w.writeUint64(uint64(l))
+		}
+		e.w.writestr(v)
+	}
+}
+
+func (e *bincEncDriver) encodeStringBytes(c charEncoding, v []byte) {
+	l := uint64(len(v))
+	e.encBytesLen(c, l)
+	if l > 0 {
+		e.w.writeb(v)
+	}
+}
+
+func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) {
+	//TODO: support bincUnicodeOther (for now, just use string or bytearray)
+	if c == c_RAW {
+		e.encLen(bincVdByteArray<<4, length)
+	} else {
+		e.encLen(bincVdString<<4, length)
+	}
+}
+
+func (e *bincEncDriver) encLen(bd byte, l uint64) {
+	if l < 12 {
+		e.w.writen1(bd | uint8(l+4))
+	} else {
+		e.encLenNumber(bd, l)
+	}
+}
+
+func (e *bincEncDriver) encLenNumber(bd byte, v uint64) {
+	switch {
+	case v <= math.MaxUint8:
+		e.w.writen2(bd, byte(v))
+	case v <= math.MaxUint16:
+		e.w.writen1(bd | 0x01)
+		e.w.writeUint16(uint16(v))
+	case v <= math.MaxUint32:
+		e.w.writen1(bd | 0x02)
+		e.w.writeUint32(uint32(v))
+	default:
+		e.w.writen1(bd | 0x03)
+		e.w.writeUint64(uint64(v))
+	}
+}
+
+//------------------------------------
+
+type bincDecDriver struct {
+	r      decReader
+	bdRead bool
+	bdType valueType
+	bd     byte
+	vd     byte
+	vs     byte
+	b      [8]byte
+	m      map[uint32]string // symbols (use uint32 as key, as map optimizes for it)
+}
+
+func (d *bincDecDriver) initReadNext() {
+	if d.bdRead {
+		return
+	}
+	d.bd = d.r.readn1()
+	d.vd = d.bd >> 4
+	d.vs = d.bd & 0x0f
+	d.bdRead = true
+	d.bdType = valueTypeUnset
+}
+
+func (d *bincDecDriver) currentEncodedType() valueType {
+	if d.bdType == valueTypeUnset {
+		switch d.vd {
+		case bincVdSpecial:
+			switch d.vs {
+			case bincSpNil:
+				d.bdType = valueTypeNil
+			case bincSpFalse, bincSpTrue:
+				d.bdType = valueTypeBool
+			case bincSpNan, bincSpNegInf, bincSpPosInf, bincSpZeroFloat:
+				d.bdType = valueTypeFloat
+			case bincSpZero:
+				d.bdType = valueTypeUint
+			case bincSpNegOne:
+				d.bdType = valueTypeInt
+			default:
+				decErr("currentEncodedType: Unrecognized special value 0x%x", d.vs)
+			}
+		case bincVdSmallInt:
+			d.bdType = valueTypeUint
+		case bincVdPosInt:
+			d.bdType = valueTypeUint
+		case bincVdNegInt:
+			d.bdType = valueTypeInt
+		case bincVdFloat:
+			d.bdType = valueTypeFloat
+		case bincVdString:
+			d.bdType = valueTypeString
+		case bincVdSymbol:
+			d.bdType = valueTypeSymbol
+		case bincVdByteArray:
+			d.bdType = valueTypeBytes
+		case bincVdTimestamp:
+			d.bdType = valueTypeTimestamp
+		case bincVdCustomExt:
+			d.bdType = valueTypeExt
+		case bincVdArray:
+			d.bdType = valueTypeArray
+		case bincVdMap:
+			d.bdType = valueTypeMap
+		default:
+			decErr("currentEncodedType: Unrecognized d.vd: 0x%x", d.vd)
+		}
+	}
+	return d.bdType
+}
+
+func (d *bincDecDriver) tryDecodeAsNil() bool {
+	if d.bd == bincVdSpecial<<4|bincSpNil {
+		d.bdRead = false
+		return true
+	}
+	return false
+}
+
+func (d *bincDecDriver) isBuiltinType(rt uintptr) bool {
+	return rt == timeTypId
+}
+
+func (d *bincDecDriver) decodeBuiltin(rt uintptr, v interface{}) {
+	switch rt {
+	case timeTypId:
+		if d.vd != bincVdTimestamp {
+			decErr("Invalid d.vd. Expecting 0x%x. Received: 0x%x", bincVdTimestamp, d.vd)
+		}
+		tt, err := decodeTime(d.r.readn(int(d.vs)))
+		if err != nil {
+			panic(err)
+		}
+		var vt *time.Time = v.(*time.Time)
+		*vt = tt
+		d.bdRead = false
+	}
+}
+
+func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) {
+	if vs&0x8 == 0 {
+		d.r.readb(d.b[0:defaultLen])
+	} else {
+		l := d.r.readn1()
+		if l > 8 {
+			decErr("At most 8 bytes used to represent float. Received: %v bytes", l)
+		}
+		for i := l; i < 8; i++ {
+			d.b[i] = 0
+		}
+		d.r.readb(d.b[0:l])
+	}
+}
+
+func (d *bincDecDriver) decFloat() (f float64) {
+	//if true { f = math.Float64frombits(d.r.readUint64()); break; }
+	switch vs := d.vs; vs & 0x7 {
+	case bincFlBin32:
+		d.decFloatPre(vs, 4)
+		f = float64(math.Float32frombits(bigen.Uint32(d.b[0:4])))
+	case bincFlBin64:
+		d.decFloatPre(vs, 8)
+		f = math.Float64frombits(bigen.Uint64(d.b[0:8]))
+	default:
+		decErr("only float32 and float64 are supported. d.vd: 0x%x, d.vs: 0x%x", d.vd, d.vs)
+	}
+	return
+}
+
+func (d *bincDecDriver) decUint() (v uint64) {
+	// need to inline the code (interface conversion and type assertion expensive)
+	switch d.vs {
+	case 0:
+		v = uint64(d.r.readn1())
+	case 1:
+		d.r.readb(d.b[6:])
+		v = uint64(bigen.Uint16(d.b[6:]))
+	case 2:
+		d.b[4] = 0
+		d.r.readb(d.b[5:])
+		v = uint64(bigen.Uint32(d.b[4:]))
+	case 3:
+		d.r.readb(d.b[4:])
+		v = uint64(bigen.Uint32(d.b[4:]))
+	case 4, 5, 6:
+		lim := int(7 - d.vs)
+		d.r.readb(d.b[lim:])
+		for i := 0; i < lim; i++ {
+			d.b[i] = 0
+		}
+		v = uint64(bigen.Uint64(d.b[:]))
+	case 7:
+		d.r.readb(d.b[:])
+		v = uint64(bigen.Uint64(d.b[:]))
+	default:
+		decErr("unsigned integers with greater than 64 bits of precision not supported")
+	}
+	return
+}
+
+func (d *bincDecDriver) decIntAny() (ui uint64, i int64, neg bool) {
+	switch d.vd {
+	case bincVdPosInt:
+		ui = d.decUint()
+		i = int64(ui)
+	case bincVdNegInt:
+		ui = d.decUint()
+		i = -(int64(ui))
+		neg = true
+	case bincVdSmallInt:
+		i = int64(d.vs) + 1
+		ui = uint64(d.vs) + 1
+	case bincVdSpecial:
+		switch d.vs {
+		case bincSpZero:
+			//i = 0
+		case bincSpNegOne:
+			neg = true
+			ui = 1
+			i = -1
+		default:
+			decErr("numeric decode fails for special value: d.vs: 0x%x", d.vs)
+		}
+	default:
+		decErr("number can only be decoded from uint or int values. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd)
+	}
+	return
+}
+
+func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) {
+	_, i, _ = d.decIntAny()
+	checkOverflow(0, i, bitsize)
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decodeUint(bitsize uint8) (ui uint64) {
+	ui, i, neg := d.decIntAny()
+	if neg {
+		decErr("Assigning negative signed value: %v, to unsigned type", i)
+	}
+	checkOverflow(ui, 0, bitsize)
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
+	switch d.vd {
+	case bincVdSpecial:
+		d.bdRead = false
+		switch d.vs {
+		case bincSpNan:
+			return math.NaN()
+		case bincSpPosInf:
+			return math.Inf(1)
+		case bincSpZeroFloat, bincSpZero:
+			return
+		case bincSpNegInf:
+			return math.Inf(-1)
+		default:
+			decErr("Invalid d.vs decoding float where d.vd=bincVdSpecial: %v", d.vs)
+		}
+	case bincVdFloat:
+		f = d.decFloat()
+	default:
+		_, i, _ := d.decIntAny()
+		f = float64(i)
+	}
+	checkOverflowFloat32(f, chkOverflow32)
+	d.bdRead = false
+	return
+}
+
+// bool can be decoded from bool only (single byte).
+func (d *bincDecDriver) decodeBool() (b bool) {
+	switch d.bd {
+	case (bincVdSpecial | bincSpFalse):
+		// b = false
+	case (bincVdSpecial | bincSpTrue):
+		b = true
+	default:
+		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) readMapLen() (length int) {
+	if d.vd != bincVdMap {
+		decErr("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd)
+	}
+	length = d.decLen()
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) readArrayLen() (length int) {
+	if d.vd != bincVdArray {
+		decErr("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd)
+	}
+	length = d.decLen()
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decLen() int {
+	if d.vs <= 3 {
+		return int(d.decUint())
+	}
+	return int(d.vs - 4)
+}
+
+func (d *bincDecDriver) decodeString() (s string) {
+	switch d.vd {
+	case bincVdString, bincVdByteArray:
+		if length := d.decLen(); length > 0 {
+			s = string(d.r.readn(length))
+		}
+	case bincVdSymbol:
+		//from vs: extract numSymbolBytes, containsStringVal, strLenPrecision,
+		//extract symbol
+		//if containsStringVal, read it and put in map
+		//else look in map for string value
+		var symbol uint32
+		vs := d.vs
+		//fmt.Printf(">>>> d.vs: 0b%b, & 0x8: %v, & 0x4: %v\n", d.vs, vs & 0x8, vs & 0x4)
+		if vs&0x8 == 0 {
+			symbol = uint32(d.r.readn1())
+		} else {
+			symbol = uint32(d.r.readUint16())
+		}
+		if d.m == nil {
+			d.m = make(map[uint32]string, 16)
+		}
+
+		if vs&0x4 == 0 {
+			s = d.m[symbol]
+		} else {
+			var slen int
+			switch vs & 0x3 {
+			case 0:
+				slen = int(d.r.readn1())
+			case 1:
+				slen = int(d.r.readUint16())
+			case 2:
+				slen = int(d.r.readUint32())
+			case 3:
+				slen = int(d.r.readUint64())
+			}
+			s = string(d.r.readn(slen))
+			d.m[symbol] = s
+		}
+	default:
+		decErr("Invalid d.vd for string. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x",
+			bincVdString, bincVdByteArray, bincVdSymbol, d.vd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
+	var clen int
+	switch d.vd {
+	case bincVdString, bincVdByteArray:
+		clen = d.decLen()
+	default:
+		decErr("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x",
+			bincVdString, bincVdByteArray, d.vd)
+	}
+	if clen > 0 {
+		// if no contents in stream, don't update the passed byteslice
+		if len(bs) != clen {
+			if len(bs) > clen {
+				bs = bs[:clen]
+			} else {
+				bs = make([]byte, clen)
+			}
+			bsOut = bs
+			changed = true
+		}
+		d.r.readb(bs)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) {
+	switch d.vd {
+	case bincVdCustomExt:
+		l := d.decLen()
+		xtag = d.r.readn1()
+		if verifyTag && xtag != tag {
+			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+		}
+		xbs = d.r.readn(l)
+	case bincVdByteArray:
+		xbs, _ = d.decodeBytes(nil)
+	default:
+		decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *bincDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
+	d.initReadNext()
+
+	switch d.vd {
+	case bincVdSpecial:
+		switch d.vs {
+		case bincSpNil:
+			vt = valueTypeNil
+		case bincSpFalse:
+			vt = valueTypeBool
+			v = false
+		case bincSpTrue:
+			vt = valueTypeBool
+			v = true
+		case bincSpNan:
+			vt = valueTypeFloat
+			v = math.NaN()
+		case bincSpPosInf:
+			vt = valueTypeFloat
+			v = math.Inf(1)
+		case bincSpNegInf:
+			vt = valueTypeFloat
+			v = math.Inf(-1)
+		case bincSpZeroFloat:
+			vt = valueTypeFloat
+			v = float64(0)
+		case bincSpZero:
+			vt = valueTypeUint
+			v = int64(0) // int8(0)
+		case bincSpNegOne:
+			vt = valueTypeInt
+			v = int64(-1) // int8(-1)
+		default:
+			decErr("decodeNaked: Unrecognized special value 0x%x", d.vs)
+		}
+	case bincVdSmallInt:
+		vt = valueTypeUint
+		v = uint64(int8(d.vs)) + 1 // int8(d.vs) + 1
+	case bincVdPosInt:
+		vt = valueTypeUint
+		v = d.decUint()
+	case bincVdNegInt:
+		vt = valueTypeInt
+		v = -(int64(d.decUint()))
+	case bincVdFloat:
+		vt = valueTypeFloat
+		v = d.decFloat()
+	case bincVdSymbol:
+		vt = valueTypeSymbol
+		v = d.decodeString()
+	case bincVdString:
+		vt = valueTypeString
+		v = d.decodeString()
+	case bincVdByteArray:
+		vt = valueTypeBytes
+		v, _ = d.decodeBytes(nil)
+	case bincVdTimestamp:
+		vt = valueTypeTimestamp
+		tt, err := decodeTime(d.r.readn(int(d.vs)))
+		if err != nil {
+			panic(err)
+		}
+		v = tt
+	case bincVdCustomExt:
+		vt = valueTypeExt
+		l := d.decLen()
+		var re RawExt
+		re.Tag = d.r.readn1()
+		re.Data = d.r.readn(l)
+		v = &re
+		vt = valueTypeExt
+	case bincVdArray:
+		vt = valueTypeArray
+		decodeFurther = true
+	case bincVdMap:
+		vt = valueTypeMap
+		decodeFurther = true
+	default:
+		decErr("decodeNaked: Unrecognized d.vd: 0x%x", d.vd)
+	}
+
+	if !decodeFurther {
+		d.bdRead = false
+	}
+	return
+}
+
+//------------------------------------
+
+//BincHandle is a Handle for the Binc Schema-Free Encoding Format
+//defined at https://github.com/ugorji/binc .
+//
+//BincHandle currently supports all Binc features with the following EXCEPTIONS:
+//  - only integers up to 64 bits of precision are supported.
+//    big integers are unsupported.
+//  - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types).
+//    extended precision and decimal IEEE 754 floats are unsupported.
+//  - Only UTF-8 strings supported.
+//    Unicode_Other Binc types (UTF16, UTF32) are currently unsupported.
+//Note that these EXCEPTIONS are temporary and full support is possible and may happen soon.
+type BincHandle struct {
+	BasicHandle
+}
+
+func (h *BincHandle) newEncDriver(w encWriter) encDriver {
+	return &bincEncDriver{w: w}
+}
+
+func (h *BincHandle) newDecDriver(r decReader) decDriver {
+	return &bincDecDriver{r: r}
+}
+
+func (_ *BincHandle) writeExt() bool {
+	return true
+}
+
+func (h *BincHandle) getBasicHandle() *BasicHandle {
+	return &h.BasicHandle
+}

+ 1002 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/codecs_test.go

@@ -0,0 +1,1002 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// Test works by using a slice of interfaces.
+// It can test for encoding/decoding into/from a nil interface{}
+// or passing the object to encode/decode into.
+//
+// There are basically 2 main tests here.
+// First test internally encodes and decodes things and verifies that
+// the artifact was as expected.
+// Second test will use python msgpack to create a bunch of golden files,
+// read those files, and compare them to what it should be. It then
+// writes those files back out and compares the byte streams.
+//
+// Taken together, the tests are pretty extensive.
+
+import (
+	"bytes"
+	"encoding/gob"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"math"
+	"net"
+	"net/rpc"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"strconv"
+	"sync/atomic"
+	"testing"
+	"time"
+)
+
+type testVerifyArg int
+
+const (
+	testVerifyMapTypeSame testVerifyArg = iota
+	testVerifyMapTypeStrIntf
+	testVerifyMapTypeIntfIntf
+	// testVerifySliceIntf
+	testVerifyForPython
+)
+
+var (
+	testInitDebug      bool
+	testUseIoEncDec    bool
+	testStructToArray  bool
+	testWriteNoSymbols bool
+
+	_                         = fmt.Printf
+	skipVerifyVal interface{} = &(struct{}{})
+
+	// For Go Time, do not use a descriptive timezone.
+	// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
+	// The Offset already tells what the offset should be, if not on UTC and unknown zone name.
+	timeLoc        = time.FixedZone("", -8*60*60) // UTC-08:00 //time.UTC-8
+	timeToCompare1 = time.Date(2012, 2, 2, 2, 2, 2, 2000, timeLoc)
+	timeToCompare2 = time.Date(1900, 2, 2, 2, 2, 2, 2000, timeLoc)
+	timeToCompare3 = time.Unix(0, 0).UTC()
+	timeToCompare4 = time.Time{}.UTC()
+
+	table              []interface{} // main items we encode
+	tableVerify        []interface{} // we verify encoded things against this after decode
+	tableTestNilVerify []interface{} // for nil interface, use this to verify (rules are different)
+	tablePythonVerify  []interface{} // for verifying for python, since Python sometimes
+	// will encode a float32 as float64, or large int as uint
+	testRpcInt   = new(TestRpcInt)
+	testMsgpackH = &MsgpackHandle{}
+	testBincH    = &BincHandle{}
+	testSimpleH  = &SimpleHandle{}
+)
+
+func testInitFlags() {
+	// delete(testDecOpts.ExtFuncs, timeTyp)
+	flag.BoolVar(&testInitDebug, "tg", false, "Test Debug")
+	flag.BoolVar(&testUseIoEncDec, "ti", false, "Use IO Reader/Writer for Marshal/Unmarshal")
+	flag.BoolVar(&testStructToArray, "ts", false, "Set StructToArray option")
+	flag.BoolVar(&testWriteNoSymbols, "tn", false, "Set NoSymbols option")
+}
+
+type AnonInTestStruc struct {
+	AS        string
+	AI64      int64
+	AI16      int16
+	AUi64     uint64
+	ASslice   []string
+	AI64slice []int64
+}
+
+type TestStruc struct {
+	S    string
+	I64  int64
+	I16  int16
+	Ui64 uint64
+	Ui8  uint8
+	B    bool
+	By   byte
+
+	Sslice    []string
+	I64slice  []int64
+	I16slice  []int16
+	Ui64slice []uint64
+	Ui8slice  []uint8
+	Bslice    []bool
+	Byslice   []byte
+
+	Islice    []interface{}
+	Iptrslice []*int64
+
+	AnonInTestStruc
+
+	//M map[interface{}]interface{}  `json:"-",bson:"-"`
+	Ms    map[string]interface{}
+	Msi64 map[string]int64
+
+	Nintf      interface{} //don't set this, so we can test for nil
+	T          time.Time
+	Nmap       map[string]bool //don't set this, so we can test for nil
+	Nslice     []byte          //don't set this, so we can test for nil
+	Nint64     *int64          //don't set this, so we can test for nil
+	Mtsptr     map[string]*TestStruc
+	Mts        map[string]TestStruc
+	Its        []*TestStruc
+	Nteststruc *TestStruc
+}
+
+type TestABC struct {
+	A, B, C string
+}
+
+type TestRpcInt struct {
+	i int
+}
+
+func (r *TestRpcInt) Update(n int, res *int) error      { r.i = n; *res = r.i; return nil }
+func (r *TestRpcInt) Square(ignore int, res *int) error { *res = r.i * r.i; return nil }
+func (r *TestRpcInt) Mult(n int, res *int) error        { *res = r.i * n; return nil }
+func (r *TestRpcInt) EchoStruct(arg TestABC, res *string) error {
+	*res = fmt.Sprintf("%#v", arg)
+	return nil
+}
+func (r *TestRpcInt) Echo123(args []string, res *string) error {
+	*res = fmt.Sprintf("%#v", args)
+	return nil
+}
+
+func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) {
+	//for python msgpack,
+	//  - all positive integers are unsigned 64-bit ints
+	//  - all floats are float64
+	switch iv := v.(type) {
+	case int8:
+		if iv > 0 {
+			v2 = uint64(iv)
+		} else {
+			v2 = int64(iv)
+		}
+	case int16:
+		if iv > 0 {
+			v2 = uint64(iv)
+		} else {
+			v2 = int64(iv)
+		}
+	case int32:
+		if iv > 0 {
+			v2 = uint64(iv)
+		} else {
+			v2 = int64(iv)
+		}
+	case int64:
+		if iv > 0 {
+			v2 = uint64(iv)
+		} else {
+			v2 = int64(iv)
+		}
+	case uint8:
+		v2 = uint64(iv)
+	case uint16:
+		v2 = uint64(iv)
+	case uint32:
+		v2 = uint64(iv)
+	case uint64:
+		v2 = uint64(iv)
+	case float32:
+		v2 = float64(iv)
+	case float64:
+		v2 = float64(iv)
+	case []interface{}:
+		m2 := make([]interface{}, len(iv))
+		for j, vj := range iv {
+			m2[j] = testVerifyVal(vj, arg)
+		}
+		v2 = m2
+	case map[string]bool:
+		switch arg {
+		case testVerifyMapTypeSame:
+			m2 := make(map[string]bool)
+			for kj, kv := range iv {
+				m2[kj] = kv
+			}
+			v2 = m2
+		case testVerifyMapTypeStrIntf, testVerifyForPython:
+			m2 := make(map[string]interface{})
+			for kj, kv := range iv {
+				m2[kj] = kv
+			}
+			v2 = m2
+		case testVerifyMapTypeIntfIntf:
+			m2 := make(map[interface{}]interface{})
+			for kj, kv := range iv {
+				m2[kj] = kv
+			}
+			v2 = m2
+		}
+	case map[string]interface{}:
+		switch arg {
+		case testVerifyMapTypeSame:
+			m2 := make(map[string]interface{})
+			for kj, kv := range iv {
+				m2[kj] = testVerifyVal(kv, arg)
+			}
+			v2 = m2
+		case testVerifyMapTypeStrIntf, testVerifyForPython:
+			m2 := make(map[string]interface{})
+			for kj, kv := range iv {
+				m2[kj] = testVerifyVal(kv, arg)
+			}
+			v2 = m2
+		case testVerifyMapTypeIntfIntf:
+			m2 := make(map[interface{}]interface{})
+			for kj, kv := range iv {
+				m2[kj] = testVerifyVal(kv, arg)
+			}
+			v2 = m2
+		}
+	case map[interface{}]interface{}:
+		m2 := make(map[interface{}]interface{})
+		for kj, kv := range iv {
+			m2[testVerifyVal(kj, arg)] = testVerifyVal(kv, arg)
+		}
+		v2 = m2
+	case time.Time:
+		switch arg {
+		case testVerifyForPython:
+			if iv2 := iv.UnixNano(); iv2 > 0 {
+				v2 = uint64(iv2)
+			} else {
+				v2 = int64(iv2)
+			}
+		default:
+			v2 = v
+		}
+	default:
+		v2 = v
+	}
+	return
+}
+
+func testInit() {
+	gob.Register(new(TestStruc))
+	if testInitDebug {
+		ts0 := newTestStruc(2, false)
+		fmt.Printf("====> depth: %v, ts: %#v\n", 2, ts0)
+	}
+
+	testBincH.StructToArray = testStructToArray
+	if testWriteNoSymbols {
+		testBincH.AsSymbols = AsSymbolNone
+	} else {
+		testBincH.AsSymbols = AsSymbolAll
+	}
+	testMsgpackH.StructToArray = testStructToArray
+	testMsgpackH.RawToString = true
+	// testMsgpackH.AddExt(byteSliceTyp, 0, testMsgpackH.BinaryEncodeExt, testMsgpackH.BinaryDecodeExt)
+	// testMsgpackH.AddExt(timeTyp, 1, testMsgpackH.TimeEncodeExt, testMsgpackH.TimeDecodeExt)
+	timeEncExt := func(rv reflect.Value) ([]byte, error) {
+		return encodeTime(rv.Interface().(time.Time)), nil
+	}
+	timeDecExt := func(rv reflect.Value, bs []byte) error {
+		tt, err := decodeTime(bs)
+		if err == nil {
+			rv.Set(reflect.ValueOf(tt))
+		}
+		return err
+	}
+
+	// add extensions for msgpack, simple for time.Time, so we can encode/decode same way.
+	testMsgpackH.AddExt(timeTyp, 1, timeEncExt, timeDecExt)
+	testSimpleH.AddExt(timeTyp, 1, timeEncExt, timeDecExt)
+
+	primitives := []interface{}{
+		int8(-8),
+		int16(-1616),
+		int32(-32323232),
+		int64(-6464646464646464),
+		uint8(192),
+		uint16(1616),
+		uint32(32323232),
+		uint64(6464646464646464),
+		byte(192),
+		float32(-3232.0),
+		float64(-6464646464.0),
+		float32(3232.0),
+		float64(6464646464.0),
+		false,
+		true,
+		nil,
+		"someday",
+		"",
+		"bytestring",
+		timeToCompare1,
+		timeToCompare2,
+		timeToCompare3,
+		timeToCompare4,
+	}
+	mapsAndStrucs := []interface{}{
+		map[string]bool{
+			"true":  true,
+			"false": false,
+		},
+		map[string]interface{}{
+			"true":         "True",
+			"false":        false,
+			"uint16(1616)": uint16(1616),
+		},
+		//add a complex combo map in here. (map has list which has map)
+		//note that after the first thing, everything else should be generic.
+		map[string]interface{}{
+			"list": []interface{}{
+				int16(1616),
+				int32(32323232),
+				true,
+				float32(-3232.0),
+				map[string]interface{}{
+					"TRUE":  true,
+					"FALSE": false,
+				},
+				[]interface{}{true, false},
+			},
+			"int32":        int32(32323232),
+			"bool":         true,
+			"LONG STRING":  "123456789012345678901234567890123456789012345678901234567890",
+			"SHORT STRING": "1234567890",
+		},
+		map[interface{}]interface{}{
+			true:       "true",
+			uint8(138): false,
+			"false":    uint8(200),
+		},
+		newTestStruc(0, false),
+	}
+
+	table = []interface{}{}
+	table = append(table, primitives...)    //0-19 are primitives
+	table = append(table, primitives)       //20 is a list of primitives
+	table = append(table, mapsAndStrucs...) //21-24 are maps. 25 is a *struct
+
+	tableVerify = make([]interface{}, len(table))
+	tableTestNilVerify = make([]interface{}, len(table))
+	tablePythonVerify = make([]interface{}, len(table))
+
+	lp := len(primitives)
+	av := tableVerify
+	for i, v := range table {
+		if i == lp+3 {
+			av[i] = skipVerifyVal
+			continue
+		}
+		//av[i] = testVerifyVal(v, testVerifyMapTypeSame)
+		switch v.(type) {
+		case []interface{}:
+			av[i] = testVerifyVal(v, testVerifyMapTypeSame)
+		case map[string]interface{}:
+			av[i] = testVerifyVal(v, testVerifyMapTypeSame)
+		case map[interface{}]interface{}:
+			av[i] = testVerifyVal(v, testVerifyMapTypeSame)
+		default:
+			av[i] = v
+		}
+	}
+
+	av = tableTestNilVerify
+	for i, v := range table {
+		if i > lp+3 {
+			av[i] = skipVerifyVal
+			continue
+		}
+		av[i] = testVerifyVal(v, testVerifyMapTypeStrIntf)
+	}
+
+	av = tablePythonVerify
+	for i, v := range table {
+		if i > lp+3 {
+			av[i] = skipVerifyVal
+			continue
+		}
+		av[i] = testVerifyVal(v, testVerifyForPython)
+	}
+
+	tablePythonVerify = tablePythonVerify[:24]
+}
+
+func testUnmarshal(v interface{}, data []byte, h Handle) error {
+	if testUseIoEncDec {
+		return NewDecoder(bytes.NewBuffer(data), h).Decode(v)
+	}
+	return NewDecoderBytes(data, h).Decode(v)
+}
+
+func testMarshal(v interface{}, h Handle) (bs []byte, err error) {
+	if testUseIoEncDec {
+		var buf bytes.Buffer
+		err = NewEncoder(&buf, h).Encode(v)
+		bs = buf.Bytes()
+		return
+	}
+	err = NewEncoderBytes(&bs, h).Encode(v)
+	return
+}
+
+func testMarshalErr(v interface{}, h Handle, t *testing.T, name string) (bs []byte, err error) {
+	if bs, err = testMarshal(v, h); err != nil {
+		logT(t, "Error encoding %s: %v, Err: %v", name, v, err)
+		t.FailNow()
+	}
+	return
+}
+
+func testUnmarshalErr(v interface{}, data []byte, h Handle, t *testing.T, name string) (err error) {
+	if err = testUnmarshal(v, data, h); err != nil {
+		logT(t, "Error Decoding into %s: %v, Err: %v", name, v, err)
+		t.FailNow()
+	}
+	return
+}
+
+func newTestStruc(depth int, bench bool) (ts *TestStruc) {
+	var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464
+
+	ts = &TestStruc{
+		S:    "some string",
+		I64:  math.MaxInt64 * 2 / 3, // 64,
+		I16:  16,
+		Ui64: uint64(int64(math.MaxInt64 * 2 / 3)), // 64, //don't use MaxUint64, as bson can't write it
+		Ui8:  160,
+		B:    true,
+		By:   5,
+
+		Sslice:    []string{"one", "two", "three"},
+		I64slice:  []int64{1, 2, 3},
+		I16slice:  []int16{4, 5, 6},
+		Ui64slice: []uint64{137, 138, 139},
+		Ui8slice:  []uint8{210, 211, 212},
+		Bslice:    []bool{true, false, true, false},
+		Byslice:   []byte{13, 14, 15},
+
+		Islice: []interface{}{"true", true, "no", false, uint64(288), float64(0.4)},
+
+		Ms: map[string]interface{}{
+			"true":     "true",
+			"int64(9)": false,
+		},
+		Msi64: map[string]int64{
+			"one": 1,
+			"two": 2,
+		},
+		T: timeToCompare1,
+		AnonInTestStruc: AnonInTestStruc{
+			AS:        "A-String",
+			AI64:      64,
+			AI16:      16,
+			AUi64:     64,
+			ASslice:   []string{"Aone", "Atwo", "Athree"},
+			AI64slice: []int64{1, 2, 3},
+		},
+	}
+	//For benchmarks, some things will not work.
+	if !bench {
+		//json and bson require string keys in maps
+		//ts.M = map[interface{}]interface{}{
+		//	true: "true",
+		//	int8(9): false,
+		//}
+		//gob cannot encode nil in element in array (encodeArray: nil element)
+		ts.Iptrslice = []*int64{nil, &i64a, nil, &i64b, nil, &i64c, nil, &i64d, nil}
+		// ts.Iptrslice = nil
+	}
+	if depth > 0 {
+		depth--
+		if ts.Mtsptr == nil {
+			ts.Mtsptr = make(map[string]*TestStruc)
+		}
+		if ts.Mts == nil {
+			ts.Mts = make(map[string]TestStruc)
+		}
+		ts.Mtsptr["0"] = newTestStruc(depth, bench)
+		ts.Mts["0"] = *(ts.Mtsptr["0"])
+		ts.Its = append(ts.Its, ts.Mtsptr["0"])
+	}
+	return
+}
+
+// doTestCodecTableOne allows us test for different variations based on arguments passed.
+func doTestCodecTableOne(t *testing.T, testNil bool, h Handle,
+	vs []interface{}, vsVerify []interface{}) {
+	//if testNil, then just test for when a pointer to a nil interface{} is passed. It should work.
+	//Current setup allows us test (at least manually) the nil interface or typed interface.
+	logT(t, "================ TestNil: %v ================\n", testNil)
+	for i, v0 := range vs {
+		logT(t, "..............................................")
+		logT(t, "         Testing: #%d:, %T, %#v\n", i, v0, v0)
+		b0, err := testMarshalErr(v0, h, t, "v0")
+		if err != nil {
+			continue
+		}
+		logT(t, "         Encoded bytes: len: %v, %v\n", len(b0), b0)
+
+		var v1 interface{}
+
+		if testNil {
+			err = testUnmarshal(&v1, b0, h)
+		} else {
+			if v0 != nil {
+				v0rt := reflect.TypeOf(v0) // ptr
+				rv1 := reflect.New(v0rt)
+				err = testUnmarshal(rv1.Interface(), b0, h)
+				v1 = rv1.Elem().Interface()
+				// v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface()
+			}
+		}
+
+		logT(t, "         v1 returned: %T, %#v", v1, v1)
+		// if v1 != nil {
+		//	logT(t, "         v1 returned: %T, %#v", v1, v1)
+		//	//we always indirect, because ptr to typed value may be passed (if not testNil)
+		//	v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface()
+		// }
+		if err != nil {
+			logT(t, "-------- Error: %v. Partial return: %v", err, v1)
+			failT(t)
+			continue
+		}
+		v0check := vsVerify[i]
+		if v0check == skipVerifyVal {
+			logT(t, "        Nil Check skipped: Decoded: %T, %#v\n", v1, v1)
+			continue
+		}
+
+		if err = deepEqual(v0check, v1); err == nil {
+			logT(t, "++++++++ Before and After marshal matched\n")
+		} else {
+			logT(t, "-------- Before and After marshal do not match: Error: %v"+
+				" ====> GOLDEN: (%T) %#v, DECODED: (%T) %#v\n", err, v0check, v0check, v1, v1)
+			failT(t)
+		}
+	}
+}
+
+func testCodecTableOne(t *testing.T, h Handle) {
+	// func TestMsgpackAllExperimental(t *testing.T) {
+	// dopts := testDecOpts(nil, nil, false, true, true),
+
+	switch v := h.(type) {
+	case *MsgpackHandle:
+		var oldWriteExt, oldRawToString bool
+		oldWriteExt, v.WriteExt = v.WriteExt, true
+		oldRawToString, v.RawToString = v.RawToString, true
+		doTestCodecTableOne(t, false, h, table, tableVerify)
+		v.WriteExt, v.RawToString = oldWriteExt, oldRawToString
+	default:
+		doTestCodecTableOne(t, false, h, table, tableVerify)
+	}
+	// func TestMsgpackAll(t *testing.T) {
+	idxTime, numPrim, numMap := 19, 23, 4
+
+	//skip []interface{} containing time.Time
+	doTestCodecTableOne(t, false, h, table[:numPrim], tableVerify[:numPrim])
+	doTestCodecTableOne(t, false, h, table[numPrim+1:], tableVerify[numPrim+1:])
+	// func TestMsgpackNilStringMap(t *testing.T) {
+	var oldMapType reflect.Type
+	v := h.getBasicHandle()
+	oldMapType, v.MapType = v.MapType, mapStrIntfTyp
+
+	//skip time.Time, []interface{} containing time.Time, last map, and newStruc
+	doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime])
+	doTestCodecTableOne(t, true, h, table[numPrim+1:numPrim+numMap], tableTestNilVerify[numPrim+1:numPrim+numMap])
+
+	v.MapType = oldMapType
+
+	// func TestMsgpackNilIntf(t *testing.T) {
+
+	//do newTestStruc and last element of map
+	doTestCodecTableOne(t, true, h, table[numPrim+numMap:], tableTestNilVerify[numPrim+numMap:])
+	//TODO? What is this one?
+	//doTestCodecTableOne(t, true, h, table[17:18], tableTestNilVerify[17:18])
+}
+
+func testCodecMiscOne(t *testing.T, h Handle) {
+	b, err := testMarshalErr(32, h, t, "32")
+	// Cannot do this nil one, because faster type assertion decoding will panic
+	// var i *int32
+	// if err = testUnmarshal(b, i, nil); err == nil {
+	// 	logT(t, "------- Expecting error because we cannot unmarshal to int32 nil ptr")
+	// 	t.FailNow()
+	// }
+	var i2 int32 = 0
+	err = testUnmarshalErr(&i2, b, h, t, "int32-ptr")
+	if i2 != int32(32) {
+		logT(t, "------- didn't unmarshal to 32: Received: %d", i2)
+		t.FailNow()
+	}
+
+	// func TestMsgpackDecodePtr(t *testing.T) {
+	ts := newTestStruc(0, false)
+	b, err = testMarshalErr(ts, h, t, "pointer-to-struct")
+	if len(b) < 40 {
+		logT(t, "------- Size must be > 40. Size: %d", len(b))
+		t.FailNow()
+	}
+	logT(t, "------- b: %v", b)
+	ts2 := new(TestStruc)
+	err = testUnmarshalErr(ts2, b, h, t, "pointer-to-struct")
+	if ts2.I64 != math.MaxInt64*2/3 {
+		logT(t, "------- Unmarshal wrong. Expect I64 = 64. Got: %v", ts2.I64)
+		t.FailNow()
+	}
+
+	// func TestMsgpackIntfDecode(t *testing.T) {
+	m := map[string]int{"A": 2, "B": 3}
+	p := []interface{}{m}
+	bs, err := testMarshalErr(p, h, t, "p")
+
+	m2 := map[string]int{}
+	p2 := []interface{}{m2}
+	err = testUnmarshalErr(&p2, bs, h, t, "&p2")
+
+	if m2["A"] != 2 || m2["B"] != 3 {
+		logT(t, "m2 not as expected: expecting: %v, got: %v", m, m2)
+		t.FailNow()
+	}
+	// log("m: %v, m2: %v, p: %v, p2: %v", m, m2, p, p2)
+	checkEqualT(t, p, p2, "p=p2")
+	checkEqualT(t, m, m2, "m=m2")
+	if err = deepEqual(p, p2); err == nil {
+		logT(t, "p and p2 match")
+	} else {
+		logT(t, "Not Equal: %v. p: %v, p2: %v", err, p, p2)
+		t.FailNow()
+	}
+	if err = deepEqual(m, m2); err == nil {
+		logT(t, "m and m2 match")
+	} else {
+		logT(t, "Not Equal: %v. m: %v, m2: %v", err, m, m2)
+		t.FailNow()
+	}
+
+	// func TestMsgpackDecodeStructSubset(t *testing.T) {
+	// test that we can decode a subset of the stream
+	mm := map[string]interface{}{"A": 5, "B": 99, "C": 333}
+	bs, err = testMarshalErr(mm, h, t, "mm")
+	type ttt struct {
+		A uint8
+		C int32
+	}
+	var t2 ttt
+	testUnmarshalErr(&t2, bs, h, t, "t2")
+	t3 := ttt{5, 333}
+	checkEqualT(t, t2, t3, "t2=t3")
+
+	// println(">>>>>")
+	// test simple arrays, non-addressable arrays, slices
+	type tarr struct {
+		A int64
+		B [3]int64
+		C []byte
+		D [3]byte
+	}
+	var tarr0 = tarr{1, [3]int64{2, 3, 4}, []byte{4, 5, 6}, [3]byte{7, 8, 9}}
+	// test both pointer and non-pointer (value)
+	for _, tarr1 := range []interface{}{tarr0, &tarr0} {
+		bs, err = testMarshalErr(tarr1, h, t, "tarr1")
+		var tarr2 tarr
+		testUnmarshalErr(&tarr2, bs, h, t, "tarr2")
+		checkEqualT(t, tarr0, tarr2, "tarr0=tarr2")
+		// fmt.Printf(">>>> err: %v. tarr1: %v, tarr2: %v\n", err, tarr0, tarr2)
+	}
+
+	// test byte array, even if empty (msgpack only)
+	if h == testMsgpackH {
+		type ystruct struct {
+			Anarray []byte
+		}
+		var ya = ystruct{}
+		testUnmarshalErr(&ya, []byte{0x91, 0x90}, h, t, "ya")
+	}
+}
+
+func testCodecEmbeddedPointer(t *testing.T, h Handle) {
+	type Z int
+	type A struct {
+		AnInt int
+	}
+	type B struct {
+		*Z
+		*A
+		MoreInt int
+	}
+	var z Z = 4
+	x1 := &B{&z, &A{5}, 6}
+	bs, err := testMarshalErr(x1, h, t, "x1")
+	// fmt.Printf("buf: len(%v): %x\n", buf.Len(), buf.Bytes())
+	var x2 = new(B)
+	err = testUnmarshalErr(x2, bs, h, t, "x2")
+	err = checkEqualT(t, x1, x2, "x1=x2")
+	_ = err
+}
+
+func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs time.Duration,
+) (port int) {
+	// rpc needs EOF, which is sent via a panic, and so must be recovered.
+	if !recoverPanicToErr {
+		logT(t, "EXPECTED. set recoverPanicToErr=true, since rpc needs EOF")
+		t.FailNow()
+	}
+	srv := rpc.NewServer()
+	srv.Register(testRpcInt)
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	// log("listener: %v", ln.Addr())
+	checkErrT(t, err)
+	port = (ln.Addr().(*net.TCPAddr)).Port
+	// var opts *DecoderOptions
+	// opts := testDecOpts
+	// opts.MapType = mapStrIntfTyp
+	// opts.RawToString = false
+	serverExitChan := make(chan bool, 1)
+	var serverExitFlag uint64 = 0
+	serverFn := func() {
+		for {
+			conn1, err1 := ln.Accept()
+			// if err1 != nil {
+			// 	//fmt.Printf("accept err1: %v\n", err1)
+			// 	continue
+			// }
+			if atomic.LoadUint64(&serverExitFlag) == 1 {
+				serverExitChan <- true
+				conn1.Close()
+				return // exit serverFn goroutine
+			}
+			if err1 == nil {
+				var sc rpc.ServerCodec = rr.ServerCodec(conn1, h)
+				srv.ServeCodec(sc)
+			}
+		}
+	}
+
+	clientFn := func(cc rpc.ClientCodec) {
+		cl := rpc.NewClientWithCodec(cc)
+		defer cl.Close()
+		var up, sq, mult int
+		var rstr string
+		// log("Calling client")
+		checkErrT(t, cl.Call("TestRpcInt.Update", 5, &up))
+		// log("Called TestRpcInt.Update")
+		checkEqualT(t, testRpcInt.i, 5, "testRpcInt.i=5")
+		checkEqualT(t, up, 5, "up=5")
+		checkErrT(t, cl.Call("TestRpcInt.Square", 1, &sq))
+		checkEqualT(t, sq, 25, "sq=25")
+		checkErrT(t, cl.Call("TestRpcInt.Mult", 20, &mult))
+		checkEqualT(t, mult, 100, "mult=100")
+		checkErrT(t, cl.Call("TestRpcInt.EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr))
+		checkEqualT(t, rstr, fmt.Sprintf("%#v", TestABC{"Aa", "Bb", "Cc"}), "rstr=")
+		checkErrT(t, cl.Call("TestRpcInt.Echo123", []string{"A1", "B2", "C3"}, &rstr))
+		checkEqualT(t, rstr, fmt.Sprintf("%#v", []string{"A1", "B2", "C3"}), "rstr=")
+	}
+
+	connFn := func() (bs net.Conn) {
+		// log("calling f1")
+		bs, err2 := net.Dial(ln.Addr().Network(), ln.Addr().String())
+		//fmt.Printf("f1. bs: %v, err2: %v\n", bs, err2)
+		checkErrT(t, err2)
+		return
+	}
+
+	exitFn := func() {
+		atomic.StoreUint64(&serverExitFlag, 1)
+		bs := connFn()
+		<-serverExitChan
+		bs.Close()
+		// serverExitChan <- true
+	}
+
+	go serverFn()
+	runtime.Gosched()
+	//time.Sleep(100 * time.Millisecond)
+	if exitSleepMs == 0 {
+		defer ln.Close()
+		defer exitFn()
+	}
+	if doRequest {
+		bs := connFn()
+		cc := rr.ClientCodec(bs, h)
+		clientFn(cc)
+	}
+	if exitSleepMs != 0 {
+		go func() {
+			defer ln.Close()
+			time.Sleep(exitSleepMs)
+			exitFn()
+		}()
+	}
+	return
+}
+
+// Comprehensive testing that generates data encoded from python msgpack,
+// and validates that our code can read and write it out accordingly.
+// We keep this unexported here, and put actual test in ext_dep_test.go.
+// This way, it can be excluded by excluding file completely.
+func doTestMsgpackPythonGenStreams(t *testing.T) {
+	logT(t, "TestPythonGenStreams")
+	tmpdir, err := ioutil.TempDir("", "golang-msgpack-test")
+	if err != nil {
+		logT(t, "-------- Unable to create temp directory\n")
+		t.FailNow()
+	}
+	defer os.RemoveAll(tmpdir)
+	logT(t, "tmpdir: %v", tmpdir)
+	cmd := exec.Command("python", "msgpack_test.py", "testdata", tmpdir)
+	//cmd.Stdin = strings.NewReader("some input")
+	//cmd.Stdout = &out
+	var cmdout []byte
+	if cmdout, err = cmd.CombinedOutput(); err != nil {
+		logT(t, "-------- Error running msgpack_test.py testdata. Err: %v", err)
+		logT(t, "         %v", string(cmdout))
+		t.FailNow()
+	}
+
+	oldMapType := testMsgpackH.MapType
+	for i, v := range tablePythonVerify {
+		testMsgpackH.MapType = oldMapType
+		//load up the golden file based on number
+		//decode it
+		//compare to in-mem object
+		//encode it again
+		//compare to output stream
+		logT(t, "..............................................")
+		logT(t, "         Testing: #%d: %T, %#v\n", i, v, v)
+		var bss []byte
+		bss, err = ioutil.ReadFile(filepath.Join(tmpdir, strconv.Itoa(i)+".golden"))
+		if err != nil {
+			logT(t, "-------- Error reading golden file: %d. Err: %v", i, err)
+			failT(t)
+			continue
+		}
+		testMsgpackH.MapType = mapStrIntfTyp
+
+		var v1 interface{}
+		if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil {
+			logT(t, "-------- Error decoding stream: %d: Err: %v", i, err)
+			failT(t)
+			continue
+		}
+		if v == skipVerifyVal {
+			continue
+		}
+		//no need to indirect, because we pass a nil ptr, so we already have the value
+		//if v1 != nil { v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface() }
+		if err = deepEqual(v, v1); err == nil {
+			logT(t, "++++++++ Objects match")
+		} else {
+			logT(t, "-------- Objects do not match: %v. Source: %T. Decoded: %T", err, v, v1)
+			logT(t, "--------   AGAINST: %#v", v)
+			logT(t, "--------   DECODED: %#v <====> %#v", v1, reflect.Indirect(reflect.ValueOf(v1)).Interface())
+			failT(t)
+		}
+		bsb, err := testMarshal(v1, testMsgpackH)
+		if err != nil {
+			logT(t, "Error encoding to stream: %d: Err: %v", i, err)
+			failT(t)
+			continue
+		}
+		if err = deepEqual(bsb, bss); err == nil {
+			logT(t, "++++++++ Bytes match")
+		} else {
+			logT(t, "???????? Bytes do not match. %v.", err)
+			xs := "--------"
+			if reflect.ValueOf(v).Kind() == reflect.Map {
+				xs = "        "
+				logT(t, "%s It's a map. Ok that they don't match (dependent on ordering).", xs)
+			} else {
+				logT(t, "%s It's not a map. They should match.", xs)
+				failT(t)
+			}
+			logT(t, "%s   FROM_FILE: %4d] %v", xs, len(bss), bss)
+			logT(t, "%s     ENCODED: %4d] %v", xs, len(bsb), bsb)
+		}
+	}
+	testMsgpackH.MapType = oldMapType
+}
+
+// To test MsgpackSpecRpc, we test 3 scenarios:
+//    - Go Client to Go RPC Service (contained within TestMsgpackRpcSpec)
+//    - Go client to Python RPC Service (contained within doTestMsgpackRpcSpecGoClientToPythonSvc)
+//    - Python Client to Go RPC Service (contained within doTestMsgpackRpcSpecPythonClientToGoSvc)
+//
+// This allows us test the different calling conventions
+//    - Go Service requires only one argument
+//    - Python Service allows multiple arguments
+
+func doTestMsgpackRpcSpecGoClientToPythonSvc(t *testing.T) {
+	openPort := "6789"
+	cmd := exec.Command("python", "msgpack_test.py", "rpc-server", openPort, "2")
+	checkErrT(t, cmd.Start())
+	time.Sleep(100 * time.Millisecond) // time for python rpc server to start
+	bs, err2 := net.Dial("tcp", ":"+openPort)
+	checkErrT(t, err2)
+	cc := MsgpackSpecRpc.ClientCodec(bs, testMsgpackH)
+	cl := rpc.NewClientWithCodec(cc)
+	defer cl.Close()
+	var rstr string
+	checkErrT(t, cl.Call("EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr))
+	//checkEqualT(t, rstr, "{'A': 'Aa', 'B': 'Bb', 'C': 'Cc'}")
+	var mArgs MsgpackSpecRpcMultiArgs = []interface{}{"A1", "B2", "C3"}
+	checkErrT(t, cl.Call("Echo123", mArgs, &rstr))
+	checkEqualT(t, rstr, "1:A1 2:B2 3:C3", "rstr=")
+}
+
+func doTestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) {
+	port := doTestRpcOne(t, MsgpackSpecRpc, testMsgpackH, false, 1*time.Second)
+	//time.Sleep(1000 * time.Millisecond)
+	cmd := exec.Command("python", "msgpack_test.py", "rpc-client-go-service", strconv.Itoa(port))
+	var cmdout []byte
+	var err error
+	if cmdout, err = cmd.CombinedOutput(); err != nil {
+		logT(t, "-------- Error running msgpack_test.py rpc-client-go-service. Err: %v", err)
+		logT(t, "         %v", string(cmdout))
+		t.FailNow()
+	}
+	checkEqualT(t, string(cmdout),
+		fmt.Sprintf("%#v\n%#v\n", []string{"A1", "B2", "C3"}, TestABC{"Aa", "Bb", "Cc"}), "cmdout=")
+}
+
+func TestBincCodecsTable(t *testing.T) {
+	testCodecTableOne(t, testBincH)
+}
+
+func TestBincCodecsMisc(t *testing.T) {
+	testCodecMiscOne(t, testBincH)
+}
+
+func TestBincCodecsEmbeddedPointer(t *testing.T) {
+	testCodecEmbeddedPointer(t, testBincH)
+}
+
+func TestSimpleCodecsTable(t *testing.T) {
+	testCodecTableOne(t, testSimpleH)
+}
+
+func TestSimpleCodecsMisc(t *testing.T) {
+	testCodecMiscOne(t, testSimpleH)
+}
+
+func TestSimpleCodecsEmbeddedPointer(t *testing.T) {
+	testCodecEmbeddedPointer(t, testSimpleH)
+}
+
+func TestMsgpackCodecsTable(t *testing.T) {
+	testCodecTableOne(t, testMsgpackH)
+}
+
+func TestMsgpackCodecsMisc(t *testing.T) {
+	testCodecMiscOne(t, testMsgpackH)
+}
+
+func TestMsgpackCodecsEmbeddedPointer(t *testing.T) {
+	testCodecEmbeddedPointer(t, testMsgpackH)
+}
+
+func TestBincRpcGo(t *testing.T) {
+	doTestRpcOne(t, GoRpc, testBincH, true, 0)
+}
+
+func _TestSimpleRpcGo(t *testing.T) {
+	doTestRpcOne(t, GoRpc, testSimpleH, true, 0)
+}
+
+func TestMsgpackRpcGo(t *testing.T) {
+	doTestRpcOne(t, GoRpc, testMsgpackH, true, 0)
+}
+
+func TestMsgpackRpcSpec(t *testing.T) {
+	doTestRpcOne(t, MsgpackSpecRpc, testMsgpackH, true, 0)
+}
+
+// TODO:
+//   Add Tests for:
+//   - decoding empty list/map in stream into a nil slice/map
+//   - binary(M|Unm)arsher support for time.Time

+ 1048 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/decode.go

@@ -0,0 +1,1048 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"io"
+	"reflect"
+	// "runtime/debug"
+)
+
+// Some tagging information for error messages.
+const (
+	msgTagDec             = "codec.decoder"
+	msgBadDesc            = "Unrecognized descriptor byte"
+	msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v"
+)
+
+// decReader abstracts the reading source, allowing implementations that can
+// read from an io.Reader or directly off a byte slice with zero-copying.
+type decReader interface {
+	readn(n int) []byte
+	readb([]byte)
+	readn1() uint8
+	readUint16() uint16
+	readUint32() uint32
+	readUint64() uint64
+}
+
+type decDriver interface {
+	initReadNext()
+	tryDecodeAsNil() bool
+	currentEncodedType() valueType
+	isBuiltinType(rt uintptr) bool
+	decodeBuiltin(rt uintptr, v interface{})
+	//decodeNaked: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
+	decodeNaked() (v interface{}, vt valueType, decodeFurther bool)
+	decodeInt(bitsize uint8) (i int64)
+	decodeUint(bitsize uint8) (ui uint64)
+	decodeFloat(chkOverflow32 bool) (f float64)
+	decodeBool() (b bool)
+	// decodeString can also decode symbols
+	decodeString() (s string)
+	decodeBytes(bs []byte) (bsOut []byte, changed bool)
+	decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
+	readMapLen() int
+	readArrayLen() int
+}
+
+type DecodeOptions struct {
+	// An instance of MapType is used during schema-less decoding of a map in the stream.
+	// If nil, we use map[interface{}]interface{}
+	MapType reflect.Type
+	// An instance of SliceType is used during schema-less decoding of an array in the stream.
+	// If nil, we use []interface{}
+	SliceType reflect.Type
+	// ErrorIfNoField controls whether an error is returned when decoding a map
+	// from a codec stream into a struct, and no matching struct field is found.
+	ErrorIfNoField bool
+}
+
+// ------------------------------------
+
+// ioDecReader is a decReader that reads off an io.Reader
+type ioDecReader struct {
+	r  io.Reader
+	br io.ByteReader
+	x  [8]byte //temp byte array re-used internally for efficiency
+}
+
+func (z *ioDecReader) readn(n int) (bs []byte) {
+	if n <= 0 {
+		return
+	}
+	bs = make([]byte, n)
+	if _, err := io.ReadAtLeast(z.r, bs, n); err != nil {
+		panic(err)
+	}
+	return
+}
+
+func (z *ioDecReader) readb(bs []byte) {
+	if _, err := io.ReadAtLeast(z.r, bs, len(bs)); err != nil {
+		panic(err)
+	}
+}
+
+func (z *ioDecReader) readn1() uint8 {
+	if z.br != nil {
+		b, err := z.br.ReadByte()
+		if err != nil {
+			panic(err)
+		}
+		return b
+	}
+	z.readb(z.x[:1])
+	return z.x[0]
+}
+
+func (z *ioDecReader) readUint16() uint16 {
+	z.readb(z.x[:2])
+	return bigen.Uint16(z.x[:2])
+}
+
+func (z *ioDecReader) readUint32() uint32 {
+	z.readb(z.x[:4])
+	return bigen.Uint32(z.x[:4])
+}
+
+func (z *ioDecReader) readUint64() uint64 {
+	z.readb(z.x[:8])
+	return bigen.Uint64(z.x[:8])
+}
+
+// ------------------------------------
+
+// bytesDecReader is a decReader that reads off a byte slice with zero copying
+type bytesDecReader struct {
+	b []byte // data
+	c int    // cursor
+	a int    // available
+}
+
+func (z *bytesDecReader) consume(n int) (oldcursor int) {
+	if z.a == 0 {
+		panic(io.EOF)
+	}
+	if n > z.a {
+		decErr("Trying to read %v bytes. Only %v available", n, z.a)
+	}
+	// z.checkAvailable(n)
+	oldcursor = z.c
+	z.c = oldcursor + n
+	z.a = z.a - n
+	return
+}
+
+func (z *bytesDecReader) readn(n int) (bs []byte) {
+	if n <= 0 {
+		return
+	}
+	c0 := z.consume(n)
+	bs = z.b[c0:z.c]
+	return
+}
+
+func (z *bytesDecReader) readb(bs []byte) {
+	copy(bs, z.readn(len(bs)))
+}
+
+func (z *bytesDecReader) readn1() uint8 {
+	c0 := z.consume(1)
+	return z.b[c0]
+}
+
+// Use binaryEncoding helper for 4 and 8 bits, but inline it for 2 bits
+// creating temp slice variable and copying it to helper function is expensive
+// for just 2 bits.
+
+func (z *bytesDecReader) readUint16() uint16 {
+	c0 := z.consume(2)
+	return uint16(z.b[c0+1]) | uint16(z.b[c0])<<8
+}
+
+func (z *bytesDecReader) readUint32() uint32 {
+	c0 := z.consume(4)
+	return bigen.Uint32(z.b[c0:z.c])
+}
+
+func (z *bytesDecReader) readUint64() uint64 {
+	c0 := z.consume(8)
+	return bigen.Uint64(z.b[c0:z.c])
+}
+
+// ------------------------------------
+
+// decFnInfo has methods for registering handling decoding of a specific type
+// based on some characteristics (builtin, extension, reflect Kind, etc)
+type decFnInfo struct {
+	ti    *typeInfo
+	d     *Decoder
+	dd    decDriver
+	xfFn  func(reflect.Value, []byte) error
+	xfTag byte
+	array bool
+}
+
+func (f *decFnInfo) builtin(rv reflect.Value) {
+	f.dd.decodeBuiltin(f.ti.rtid, rv.Addr().Interface())
+}
+
+func (f *decFnInfo) rawExt(rv reflect.Value) {
+	xtag, xbs := f.dd.decodeExt(false, 0)
+	rv.Field(0).SetUint(uint64(xtag))
+	rv.Field(1).SetBytes(xbs)
+}
+
+func (f *decFnInfo) ext(rv reflect.Value) {
+	_, xbs := f.dd.decodeExt(true, f.xfTag)
+	if fnerr := f.xfFn(rv, xbs); fnerr != nil {
+		panic(fnerr)
+	}
+}
+
+func (f *decFnInfo) binaryMarshal(rv reflect.Value) {
+	var bm binaryUnmarshaler
+	if f.ti.unmIndir == -1 {
+		bm = rv.Addr().Interface().(binaryUnmarshaler)
+	} else if f.ti.unmIndir == 0 {
+		bm = rv.Interface().(binaryUnmarshaler)
+	} else {
+		for j, k := int8(0), f.ti.unmIndir; j < k; j++ {
+			if rv.IsNil() {
+				rv.Set(reflect.New(rv.Type().Elem()))
+			}
+			rv = rv.Elem()
+		}
+		bm = rv.Interface().(binaryUnmarshaler)
+	}
+	xbs, _ := f.dd.decodeBytes(nil)
+	if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil {
+		panic(fnerr)
+	}
+}
+
+func (f *decFnInfo) kErr(rv reflect.Value) {
+	decErr("Unhandled value for kind: %v: %s", rv.Kind(), msgBadDesc)
+}
+
+func (f *decFnInfo) kString(rv reflect.Value) {
+	rv.SetString(f.dd.decodeString())
+}
+
+func (f *decFnInfo) kBool(rv reflect.Value) {
+	rv.SetBool(f.dd.decodeBool())
+}
+
+func (f *decFnInfo) kInt(rv reflect.Value) {
+	rv.SetInt(f.dd.decodeInt(intBitsize))
+}
+
+func (f *decFnInfo) kInt64(rv reflect.Value) {
+	rv.SetInt(f.dd.decodeInt(64))
+}
+
+func (f *decFnInfo) kInt32(rv reflect.Value) {
+	rv.SetInt(f.dd.decodeInt(32))
+}
+
+func (f *decFnInfo) kInt8(rv reflect.Value) {
+	rv.SetInt(f.dd.decodeInt(8))
+}
+
+func (f *decFnInfo) kInt16(rv reflect.Value) {
+	rv.SetInt(f.dd.decodeInt(16))
+}
+
+func (f *decFnInfo) kFloat32(rv reflect.Value) {
+	rv.SetFloat(f.dd.decodeFloat(true))
+}
+
+func (f *decFnInfo) kFloat64(rv reflect.Value) {
+	rv.SetFloat(f.dd.decodeFloat(false))
+}
+
+func (f *decFnInfo) kUint8(rv reflect.Value) {
+	rv.SetUint(f.dd.decodeUint(8))
+}
+
+func (f *decFnInfo) kUint64(rv reflect.Value) {
+	rv.SetUint(f.dd.decodeUint(64))
+}
+
+func (f *decFnInfo) kUint(rv reflect.Value) {
+	rv.SetUint(f.dd.decodeUint(uintBitsize))
+}
+
+func (f *decFnInfo) kUint32(rv reflect.Value) {
+	rv.SetUint(f.dd.decodeUint(32))
+}
+
+func (f *decFnInfo) kUint16(rv reflect.Value) {
+	rv.SetUint(f.dd.decodeUint(16))
+}
+
+// func (f *decFnInfo) kPtr(rv reflect.Value) {
+// 	debugf(">>>>>>> ??? decode kPtr called - shouldn't get called")
+// 	if rv.IsNil() {
+// 		rv.Set(reflect.New(rv.Type().Elem()))
+// 	}
+// 	f.d.decodeValue(rv.Elem())
+// }
+
+func (f *decFnInfo) kInterface(rv reflect.Value) {
+	// debugf("\t===> kInterface")
+	if !rv.IsNil() {
+		f.d.decodeValue(rv.Elem())
+		return
+	}
+	// nil interface:
+	// use some hieristics to set the nil interface to an
+	// appropriate value based on the first byte read (byte descriptor bd)
+	v, vt, decodeFurther := f.dd.decodeNaked()
+	if vt == valueTypeNil {
+		return
+	}
+	// Cannot decode into nil interface with methods (e.g. error, io.Reader, etc)
+	// if non-nil value in stream.
+	if num := f.ti.rt.NumMethod(); num > 0 {
+		decErr("decodeValue: Cannot decode non-nil codec value into nil %v (%v methods)",
+			f.ti.rt, num)
+	}
+	var rvn reflect.Value
+	var useRvn bool
+	switch vt {
+	case valueTypeMap:
+		if f.d.h.MapType == nil {
+			var m2 map[interface{}]interface{}
+			v = &m2
+		} else {
+			rvn = reflect.New(f.d.h.MapType).Elem()
+			useRvn = true
+		}
+	case valueTypeArray:
+		if f.d.h.SliceType == nil {
+			var m2 []interface{}
+			v = &m2
+		} else {
+			rvn = reflect.New(f.d.h.SliceType).Elem()
+			useRvn = true
+		}
+	case valueTypeExt:
+		re := v.(*RawExt)
+		var bfn func(reflect.Value, []byte) error
+		rvn, bfn = f.d.h.getDecodeExtForTag(re.Tag)
+		if bfn == nil {
+			rvn = reflect.ValueOf(*re)
+		} else if fnerr := bfn(rvn, re.Data); fnerr != nil {
+			panic(fnerr)
+		}
+		rv.Set(rvn)
+		return
+	}
+	if decodeFurther {
+		if useRvn {
+			f.d.decodeValue(rvn)
+		} else if v != nil {
+			// this v is a pointer, so we need to dereference it when done
+			f.d.decode(v)
+			rvn = reflect.ValueOf(v).Elem()
+			useRvn = true
+		}
+	}
+	if useRvn {
+		rv.Set(rvn)
+	} else if v != nil {
+		rv.Set(reflect.ValueOf(v))
+	}
+}
+
+func (f *decFnInfo) kStruct(rv reflect.Value) {
+	fti := f.ti
+	if currEncodedType := f.dd.currentEncodedType(); currEncodedType == valueTypeMap {
+		containerLen := f.dd.readMapLen()
+		if containerLen == 0 {
+			return
+		}
+		tisfi := fti.sfi
+		for j := 0; j < containerLen; j++ {
+			// var rvkencname string
+			// ddecode(&rvkencname)
+			f.dd.initReadNext()
+			rvkencname := f.dd.decodeString()
+			// rvksi := ti.getForEncName(rvkencname)
+			if k := fti.indexForEncName(rvkencname); k > -1 {
+				sfik := tisfi[k]
+				if sfik.i != -1 {
+					f.d.decodeValue(rv.Field(int(sfik.i)))
+				} else {
+					f.d.decEmbeddedField(rv, sfik.is)
+				}
+				// f.d.decodeValue(ti.field(k, rv))
+			} else {
+				if f.d.h.ErrorIfNoField {
+					decErr("No matching struct field found when decoding stream map with key: %v",
+						rvkencname)
+				} else {
+					var nilintf0 interface{}
+					f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem())
+				}
+			}
+		}
+	} else if currEncodedType == valueTypeArray {
+		containerLen := f.dd.readArrayLen()
+		if containerLen == 0 {
+			return
+		}
+		for j, si := range fti.sfip {
+			if j == containerLen {
+				break
+			}
+			if si.i != -1 {
+				f.d.decodeValue(rv.Field(int(si.i)))
+			} else {
+				f.d.decEmbeddedField(rv, si.is)
+			}
+		}
+		if containerLen > len(fti.sfip) {
+			// read remaining values and throw away
+			for j := len(fti.sfip); j < containerLen; j++ {
+				var nilintf0 interface{}
+				f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem())
+			}
+		}
+	} else {
+		decErr("Only encoded map or array can be decoded into a struct. (valueType: %x)",
+			currEncodedType)
+	}
+}
+
+func (f *decFnInfo) kSlice(rv reflect.Value) {
+	// A slice can be set from a map or array in stream.
+	currEncodedType := f.dd.currentEncodedType()
+
+	switch currEncodedType {
+	case valueTypeBytes, valueTypeString:
+		if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
+			if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 {
+				rv.SetBytes(bs2)
+			}
+			return
+		}
+	}
+
+	if shortCircuitReflectToFastPath && rv.CanAddr() {
+		switch f.ti.rtid {
+		case intfSliceTypId:
+			f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), currEncodedType, f.array)
+			return
+		case uint64SliceTypId:
+			f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), currEncodedType, f.array)
+			return
+		case int64SliceTypId:
+			f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), currEncodedType, f.array)
+			return
+		case strSliceTypId:
+			f.d.decSliceStr(rv.Addr().Interface().(*[]string), currEncodedType, f.array)
+			return
+		}
+	}
+
+	containerLen, containerLenS := decContLens(f.dd, currEncodedType)
+
+	// an array can never return a nil slice. so no need to check f.array here.
+
+	if rv.IsNil() {
+		rv.Set(reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS))
+	}
+
+	if containerLen == 0 {
+		return
+	}
+
+	if rvcap, rvlen := rv.Len(), rv.Cap(); containerLenS > rvcap {
+		if f.array { // !rv.CanSet()
+			decErr(msgDecCannotExpandArr, rvcap, containerLenS)
+		}
+		rvn := reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS)
+		if rvlen > 0 {
+			reflect.Copy(rvn, rv)
+		}
+		rv.Set(rvn)
+	} else if containerLenS > rvlen {
+		rv.SetLen(containerLenS)
+	}
+
+	for j := 0; j < containerLenS; j++ {
+		f.d.decodeValue(rv.Index(j))
+	}
+}
+
+func (f *decFnInfo) kArray(rv reflect.Value) {
+	// f.d.decodeValue(rv.Slice(0, rv.Len()))
+	f.kSlice(rv.Slice(0, rv.Len()))
+}
+
+func (f *decFnInfo) kMap(rv reflect.Value) {
+	if shortCircuitReflectToFastPath && rv.CanAddr() {
+		switch f.ti.rtid {
+		case mapStrIntfTypId:
+			f.d.decMapStrIntf(rv.Addr().Interface().(*map[string]interface{}))
+			return
+		case mapIntfIntfTypId:
+			f.d.decMapIntfIntf(rv.Addr().Interface().(*map[interface{}]interface{}))
+			return
+		case mapInt64IntfTypId:
+			f.d.decMapInt64Intf(rv.Addr().Interface().(*map[int64]interface{}))
+			return
+		case mapUint64IntfTypId:
+			f.d.decMapUint64Intf(rv.Addr().Interface().(*map[uint64]interface{}))
+			return
+		}
+	}
+
+	containerLen := f.dd.readMapLen()
+
+	if rv.IsNil() {
+		rv.Set(reflect.MakeMap(f.ti.rt))
+	}
+
+	if containerLen == 0 {
+		return
+	}
+
+	ktype, vtype := f.ti.rt.Key(), f.ti.rt.Elem()
+	ktypeId := reflect.ValueOf(ktype).Pointer()
+	for j := 0; j < containerLen; j++ {
+		rvk := reflect.New(ktype).Elem()
+		f.d.decodeValue(rvk)
+
+		// special case if a byte array.
+		// if ktype == intfTyp {
+		if ktypeId == intfTypId {
+			rvk = rvk.Elem()
+			if rvk.Type() == uint8SliceTyp {
+				rvk = reflect.ValueOf(string(rvk.Bytes()))
+			}
+		}
+		rvv := rv.MapIndex(rvk)
+		if !rvv.IsValid() {
+			rvv = reflect.New(vtype).Elem()
+		}
+
+		f.d.decodeValue(rvv)
+		rv.SetMapIndex(rvk, rvv)
+	}
+}
+
+// ----------------------------------------
+
+type decFn struct {
+	i *decFnInfo
+	f func(*decFnInfo, reflect.Value)
+}
+
+// A Decoder reads and decodes an object from an input stream in the codec format.
+type Decoder struct {
+	r decReader
+	d decDriver
+	h *BasicHandle
+	f map[uintptr]decFn
+	x []uintptr
+	s []decFn
+}
+
+// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
+//
+// For efficiency, Users are encouraged to pass in a memory buffered writer
+// (eg bufio.Reader, bytes.Buffer).
+func NewDecoder(r io.Reader, h Handle) *Decoder {
+	z := ioDecReader{
+		r: r,
+	}
+	z.br, _ = r.(io.ByteReader)
+	return &Decoder{r: &z, d: h.newDecDriver(&z), h: h.getBasicHandle()}
+}
+
+// NewDecoderBytes returns a Decoder which efficiently decodes directly
+// from a byte slice with zero copying.
+func NewDecoderBytes(in []byte, h Handle) *Decoder {
+	z := bytesDecReader{
+		b: in,
+		a: len(in),
+	}
+	return &Decoder{r: &z, d: h.newDecDriver(&z), h: h.getBasicHandle()}
+}
+
+// Decode decodes the stream from reader and stores the result in the
+// value pointed to by v. v cannot be a nil pointer. v can also be
+// a reflect.Value of a pointer.
+//
+// Note that a pointer to a nil interface is not a nil pointer.
+// If you do not know what type of stream it is, pass in a pointer to a nil interface.
+// We will decode and store a value in that nil interface.
+//
+// Sample usages:
+//   // Decoding into a non-nil typed value
+//   var f float32
+//   err = codec.NewDecoder(r, handle).Decode(&f)
+//
+//   // Decoding into nil interface
+//   var v interface{}
+//   dec := codec.NewDecoder(r, handle)
+//   err = dec.Decode(&v)
+//
+// When decoding into a nil interface{}, we will decode into an appropriate value based
+// on the contents of the stream:
+//   - Numbers are decoded as float64, int64 or uint64.
+//   - Other values are decoded appropriately depending on the type:
+//     bool, string, []byte, time.Time, etc
+//   - Extensions are decoded as RawExt (if no ext function registered for the tag)
+// Configurations exist on the Handle to override defaults
+// (e.g. for MapType, SliceType and how to decode raw bytes).
+//
+// When decoding into a non-nil interface{} value, the mode of encoding is based on the
+// type of the value. When a value is seen:
+//   - If an extension is registered for it, call that extension function
+//   - If it implements BinaryUnmarshaler, call its UnmarshalBinary(data []byte) error
+//   - Else decode it based on its reflect.Kind
+//
+// There are some special rules when decoding into containers (slice/array/map/struct).
+// Decode will typically use the stream contents to UPDATE the container.
+//   - A map can be decoded from a stream map, by updating matching keys.
+//   - A slice can be decoded from a stream array,
+//     by updating the first n elements, where n is length of the stream.
+//   - A slice can be decoded from a stream map, by decoding as if
+//     it contains a sequence of key-value pairs.
+//   - A struct can be decoded from a stream map, by updating matching fields.
+//   - A struct can be decoded from a stream array,
+//     by updating fields as they occur in the struct (by index).
+//
+// When decoding a stream map or array with length of 0 into a nil map or slice,
+// we reset the destination map or slice to a zero-length value.
+//
+// However, when decoding a stream nil, we reset the destination container
+// to its "zero" value (e.g. nil for slice/map, etc).
+//
+func (d *Decoder) Decode(v interface{}) (err error) {
+	defer panicToErr(&err)
+	d.decode(v)
+	return
+}
+
+func (d *Decoder) decode(iv interface{}) {
+	d.d.initReadNext()
+
+	switch v := iv.(type) {
+	case nil:
+		decErr("Cannot decode into nil.")
+
+	case reflect.Value:
+		d.chkPtrValue(v)
+		d.decodeValue(v.Elem())
+
+	case *string:
+		*v = d.d.decodeString()
+	case *bool:
+		*v = d.d.decodeBool()
+	case *int:
+		*v = int(d.d.decodeInt(intBitsize))
+	case *int8:
+		*v = int8(d.d.decodeInt(8))
+	case *int16:
+		*v = int16(d.d.decodeInt(16))
+	case *int32:
+		*v = int32(d.d.decodeInt(32))
+	case *int64:
+		*v = d.d.decodeInt(64)
+	case *uint:
+		*v = uint(d.d.decodeUint(uintBitsize))
+	case *uint8:
+		*v = uint8(d.d.decodeUint(8))
+	case *uint16:
+		*v = uint16(d.d.decodeUint(16))
+	case *uint32:
+		*v = uint32(d.d.decodeUint(32))
+	case *uint64:
+		*v = d.d.decodeUint(64)
+	case *float32:
+		*v = float32(d.d.decodeFloat(true))
+	case *float64:
+		*v = d.d.decodeFloat(false)
+	case *[]byte:
+		*v, _ = d.d.decodeBytes(*v)
+
+	case *[]interface{}:
+		d.decSliceIntf(v, valueTypeInvalid, false)
+	case *[]uint64:
+		d.decSliceUint64(v, valueTypeInvalid, false)
+	case *[]int64:
+		d.decSliceInt64(v, valueTypeInvalid, false)
+	case *[]string:
+		d.decSliceStr(v, valueTypeInvalid, false)
+	case *map[string]interface{}:
+		d.decMapStrIntf(v)
+	case *map[interface{}]interface{}:
+		d.decMapIntfIntf(v)
+	case *map[uint64]interface{}:
+		d.decMapUint64Intf(v)
+	case *map[int64]interface{}:
+		d.decMapInt64Intf(v)
+
+	case *interface{}:
+		d.decodeValue(reflect.ValueOf(iv).Elem())
+
+	default:
+		rv := reflect.ValueOf(iv)
+		d.chkPtrValue(rv)
+		d.decodeValue(rv.Elem())
+	}
+}
+
+func (d *Decoder) decodeValue(rv reflect.Value) {
+	d.d.initReadNext()
+
+	if d.d.tryDecodeAsNil() {
+		// If value in stream is nil, set the dereferenced value to its "zero" value (if settable)
+		if rv.Kind() == reflect.Ptr {
+			if !rv.IsNil() {
+				rv.Set(reflect.Zero(rv.Type()))
+			}
+			return
+		}
+		// for rv.Kind() == reflect.Ptr {
+		// 	rv = rv.Elem()
+		// }
+		if rv.IsValid() { // rv.CanSet() // always settable, except it's invalid
+			rv.Set(reflect.Zero(rv.Type()))
+		}
+		return
+	}
+
+	// If stream is not containing a nil value, then we can deref to the base
+	// non-pointer value, and decode into that.
+	for rv.Kind() == reflect.Ptr {
+		if rv.IsNil() {
+			rv.Set(reflect.New(rv.Type().Elem()))
+		}
+		rv = rv.Elem()
+	}
+
+	rt := rv.Type()
+	rtid := reflect.ValueOf(rt).Pointer()
+
+	// retrieve or register a focus'ed function for this type
+	// to eliminate need to do the retrieval multiple times
+
+	// if d.f == nil && d.s == nil { debugf("---->Creating new dec f map for type: %v\n", rt) }
+	var fn decFn
+	var ok bool
+	if useMapForCodecCache {
+		fn, ok = d.f[rtid]
+	} else {
+		for i, v := range d.x {
+			if v == rtid {
+				fn, ok = d.s[i], true
+				break
+			}
+		}
+	}
+	if !ok {
+		// debugf("\tCreating new dec fn for type: %v\n", rt)
+		fi := decFnInfo{ti: getTypeInfo(rtid, rt), d: d, dd: d.d}
+		fn.i = &fi
+		// An extension can be registered for any type, regardless of the Kind
+		// (e.g. type BitSet int64, type MyStruct { / * unexported fields * / }, type X []int, etc.
+		//
+		// We can't check if it's an extension byte here first, because the user may have
+		// registered a pointer or non-pointer type, meaning we may have to recurse first
+		// before matching a mapped type, even though the extension byte is already detected.
+		//
+		// NOTE: if decoding into a nil interface{}, we return a non-nil
+		// value except even if the container registers a length of 0.
+		if rtid == rawExtTypId {
+			fn.f = (*decFnInfo).rawExt
+		} else if d.d.isBuiltinType(rtid) {
+			fn.f = (*decFnInfo).builtin
+		} else if xfTag, xfFn := d.h.getDecodeExt(rtid); xfFn != nil {
+			fi.xfTag, fi.xfFn = xfTag, xfFn
+			fn.f = (*decFnInfo).ext
+		} else if supportBinaryMarshal && fi.ti.unm {
+			fn.f = (*decFnInfo).binaryMarshal
+		} else {
+			switch rk := rt.Kind(); rk {
+			case reflect.String:
+				fn.f = (*decFnInfo).kString
+			case reflect.Bool:
+				fn.f = (*decFnInfo).kBool
+			case reflect.Int:
+				fn.f = (*decFnInfo).kInt
+			case reflect.Int64:
+				fn.f = (*decFnInfo).kInt64
+			case reflect.Int32:
+				fn.f = (*decFnInfo).kInt32
+			case reflect.Int8:
+				fn.f = (*decFnInfo).kInt8
+			case reflect.Int16:
+				fn.f = (*decFnInfo).kInt16
+			case reflect.Float32:
+				fn.f = (*decFnInfo).kFloat32
+			case reflect.Float64:
+				fn.f = (*decFnInfo).kFloat64
+			case reflect.Uint8:
+				fn.f = (*decFnInfo).kUint8
+			case reflect.Uint64:
+				fn.f = (*decFnInfo).kUint64
+			case reflect.Uint:
+				fn.f = (*decFnInfo).kUint
+			case reflect.Uint32:
+				fn.f = (*decFnInfo).kUint32
+			case reflect.Uint16:
+				fn.f = (*decFnInfo).kUint16
+			// case reflect.Ptr:
+			// 	fn.f = (*decFnInfo).kPtr
+			case reflect.Interface:
+				fn.f = (*decFnInfo).kInterface
+			case reflect.Struct:
+				fn.f = (*decFnInfo).kStruct
+			case reflect.Slice:
+				fn.f = (*decFnInfo).kSlice
+			case reflect.Array:
+				fi.array = true
+				fn.f = (*decFnInfo).kArray
+			case reflect.Map:
+				fn.f = (*decFnInfo).kMap
+			default:
+				fn.f = (*decFnInfo).kErr
+			}
+		}
+		if useMapForCodecCache {
+			if d.f == nil {
+				d.f = make(map[uintptr]decFn, 16)
+			}
+			d.f[rtid] = fn
+		} else {
+			d.s = append(d.s, fn)
+			d.x = append(d.x, rtid)
+		}
+	}
+
+	fn.f(fn.i, rv)
+
+	return
+}
+
+func (d *Decoder) chkPtrValue(rv reflect.Value) {
+	// We can only decode into a non-nil pointer
+	if rv.Kind() == reflect.Ptr && !rv.IsNil() {
+		return
+	}
+	if !rv.IsValid() {
+		decErr("Cannot decode into a zero (ie invalid) reflect.Value")
+	}
+	if !rv.CanInterface() {
+		decErr("Cannot decode into a value without an interface: %v", rv)
+	}
+	rvi := rv.Interface()
+	decErr("Cannot decode into non-pointer or nil pointer. Got: %v, %T, %v",
+		rv.Kind(), rvi, rvi)
+}
+
+func (d *Decoder) decEmbeddedField(rv reflect.Value, index []int) {
+	// d.decodeValue(rv.FieldByIndex(index))
+	// nil pointers may be here; so reproduce FieldByIndex logic + enhancements
+	for _, j := range index {
+		if rv.Kind() == reflect.Ptr {
+			if rv.IsNil() {
+				rv.Set(reflect.New(rv.Type().Elem()))
+			}
+			// If a pointer, it must be a pointer to struct (based on typeInfo contract)
+			rv = rv.Elem()
+		}
+		rv = rv.Field(j)
+	}
+	d.decodeValue(rv)
+}
+
+// --------------------------------------------------
+
+// short circuit functions for common maps and slices
+
+func (d *Decoder) decSliceIntf(v *[]interface{}, currEncodedType valueType, doNotReset bool) {
+	_, containerLenS := decContLens(d.d, currEncodedType)
+	s := *v
+	if s == nil {
+		s = make([]interface{}, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]interface{}, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		d.decode(&s[j])
+	}
+	*v = s
+}
+
+func (d *Decoder) decSliceInt64(v *[]int64, currEncodedType valueType, doNotReset bool) {
+	_, containerLenS := decContLens(d.d, currEncodedType)
+	s := *v
+	if s == nil {
+		s = make([]int64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]int64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeInt(intBitsize)
+	}
+	*v = s
+}
+
+func (d *Decoder) decSliceUint64(v *[]uint64, currEncodedType valueType, doNotReset bool) {
+	_, containerLenS := decContLens(d.d, currEncodedType)
+	s := *v
+	if s == nil {
+		s = make([]uint64, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]uint64, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeUint(intBitsize)
+	}
+	*v = s
+}
+
+func (d *Decoder) decSliceStr(v *[]string, currEncodedType valueType, doNotReset bool) {
+	_, containerLenS := decContLens(d.d, currEncodedType)
+	s := *v
+	if s == nil {
+		s = make([]string, containerLenS, containerLenS)
+	} else if containerLenS > cap(s) {
+		if doNotReset {
+			decErr(msgDecCannotExpandArr, cap(s), containerLenS)
+		}
+		s = make([]string, containerLenS, containerLenS)
+		copy(s, *v)
+	} else if containerLenS > len(s) {
+		s = s[:containerLenS]
+	}
+	for j := 0; j < containerLenS; j++ {
+		// d.decode(&s[j])
+		d.d.initReadNext()
+		s[j] = d.d.decodeString()
+	}
+	*v = s
+}
+
+func (d *Decoder) decMapIntfIntf(v *map[interface{}]interface{}) {
+	containerLen := d.d.readMapLen()
+	m := *v
+	if m == nil {
+		m = make(map[interface{}]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		var mk interface{}
+		d.decode(&mk)
+		// special case if a byte array.
+		if bv, bok := mk.([]byte); bok {
+			mk = string(bv)
+		}
+		mv := m[mk]
+		d.decode(&mv)
+		m[mk] = mv
+	}
+}
+
+func (d *Decoder) decMapInt64Intf(v *map[int64]interface{}) {
+	containerLen := d.d.readMapLen()
+	m := *v
+	if m == nil {
+		m = make(map[int64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		d.d.initReadNext()
+		mk := d.d.decodeInt(intBitsize)
+		mv := m[mk]
+		d.decode(&mv)
+		m[mk] = mv
+	}
+}
+
+func (d *Decoder) decMapUint64Intf(v *map[uint64]interface{}) {
+	containerLen := d.d.readMapLen()
+	m := *v
+	if m == nil {
+		m = make(map[uint64]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		d.d.initReadNext()
+		mk := d.d.decodeUint(intBitsize)
+		mv := m[mk]
+		d.decode(&mv)
+		m[mk] = mv
+	}
+}
+
+func (d *Decoder) decMapStrIntf(v *map[string]interface{}) {
+	containerLen := d.d.readMapLen()
+	m := *v
+	if m == nil {
+		m = make(map[string]interface{}, containerLen)
+		*v = m
+	}
+	for j := 0; j < containerLen; j++ {
+		d.d.initReadNext()
+		mk := d.d.decodeString()
+		mv := m[mk]
+		d.decode(&mv)
+		m[mk] = mv
+	}
+}
+
+// ----------------------------------------
+
+func decContLens(dd decDriver, currEncodedType valueType) (containerLen, containerLenS int) {
+	if currEncodedType == valueTypeInvalid {
+		currEncodedType = dd.currentEncodedType()
+	}
+	switch currEncodedType {
+	case valueTypeArray:
+		containerLen = dd.readArrayLen()
+		containerLenS = containerLen
+	case valueTypeMap:
+		containerLen = dd.readMapLen()
+		containerLenS = containerLen * 2
+	default:
+		decErr("Only encoded map or array can be decoded into a slice. (valueType: %0x)",
+			currEncodedType)
+	}
+	return
+}
+
+func decErr(format string, params ...interface{}) {
+	doPanic(msgTagDec, format, params...)
+}

+ 1001 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/encode.go

@@ -0,0 +1,1001 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"io"
+	"reflect"
+)
+
+const (
+	// Some tagging information for error messages.
+	msgTagEnc         = "codec.encoder"
+	defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024
+	// maxTimeSecs32 = math.MaxInt32 / 60 / 24 / 366
+)
+
+// AsSymbolFlag defines what should be encoded as symbols.
+type AsSymbolFlag uint8
+
+const (
+	// AsSymbolDefault is default.
+	// Currently, this means only encode struct field names as symbols.
+	// The default is subject to change.
+	AsSymbolDefault AsSymbolFlag = iota
+
+	// AsSymbolAll means encode anything which could be a symbol as a symbol.
+	AsSymbolAll = 0xfe
+
+	// AsSymbolNone means do not encode anything as a symbol.
+	AsSymbolNone = 1 << iota
+
+	// AsSymbolMapStringKeys means encode keys in map[string]XXX as symbols.
+	AsSymbolMapStringKeysFlag
+
+	// AsSymbolStructFieldName means encode struct field names as symbols.
+	AsSymbolStructFieldNameFlag
+)
+
+// encWriter abstracting writing to a byte array or to an io.Writer.
+type encWriter interface {
+	writeUint16(uint16)
+	writeUint32(uint32)
+	writeUint64(uint64)
+	writeb([]byte)
+	writestr(string)
+	writen1(byte)
+	writen2(byte, byte)
+	atEndOfEncode()
+}
+
+// encDriver abstracts the actual codec (binc vs msgpack, etc)
+type encDriver interface {
+	isBuiltinType(rt uintptr) bool
+	encodeBuiltin(rt uintptr, v interface{})
+	encodeNil()
+	encodeInt(i int64)
+	encodeUint(i uint64)
+	encodeBool(b bool)
+	encodeFloat32(f float32)
+	encodeFloat64(f float64)
+	encodeExtPreamble(xtag byte, length int)
+	encodeArrayPreamble(length int)
+	encodeMapPreamble(length int)
+	encodeString(c charEncoding, v string)
+	encodeSymbol(v string)
+	encodeStringBytes(c charEncoding, v []byte)
+	//TODO
+	//encBignum(f *big.Int)
+	//encStringRunes(c charEncoding, v []rune)
+}
+
+type ioEncWriterWriter interface {
+	WriteByte(c byte) error
+	WriteString(s string) (n int, err error)
+	Write(p []byte) (n int, err error)
+}
+
+type ioEncStringWriter interface {
+	WriteString(s string) (n int, err error)
+}
+
+type EncodeOptions struct {
+	// Encode a struct as an array, and not as a map.
+	StructToArray bool
+
+	// AsSymbols defines what should be encoded as symbols.
+	//
+	// Encoding as symbols can reduce the encoded size significantly.
+	//
+	// However, during decoding, each string to be encoded as a symbol must
+	// be checked to see if it has been seen before. Consequently, encoding time
+	// will increase if using symbols, because string comparisons has a clear cost.
+	//
+	// Sample values:
+	//   AsSymbolNone
+	//   AsSymbolAll
+	//   AsSymbolMapStringKeys
+	//   AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag
+	AsSymbols AsSymbolFlag
+}
+
+// ---------------------------------------------
+
+type simpleIoEncWriterWriter struct {
+	w  io.Writer
+	bw io.ByteWriter
+	sw ioEncStringWriter
+}
+
+func (o *simpleIoEncWriterWriter) WriteByte(c byte) (err error) {
+	if o.bw != nil {
+		return o.bw.WriteByte(c)
+	}
+	_, err = o.w.Write([]byte{c})
+	return
+}
+
+func (o *simpleIoEncWriterWriter) WriteString(s string) (n int, err error) {
+	if o.sw != nil {
+		return o.sw.WriteString(s)
+	}
+	return o.w.Write([]byte(s))
+}
+
+func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) {
+	return o.w.Write(p)
+}
+
+// ----------------------------------------
+
+// ioEncWriter implements encWriter and can write to an io.Writer implementation
+type ioEncWriter struct {
+	w ioEncWriterWriter
+	x [8]byte // temp byte array re-used internally for efficiency
+}
+
+func (z *ioEncWriter) writeUint16(v uint16) {
+	bigen.PutUint16(z.x[:2], v)
+	z.writeb(z.x[:2])
+}
+
+func (z *ioEncWriter) writeUint32(v uint32) {
+	bigen.PutUint32(z.x[:4], v)
+	z.writeb(z.x[:4])
+}
+
+func (z *ioEncWriter) writeUint64(v uint64) {
+	bigen.PutUint64(z.x[:8], v)
+	z.writeb(z.x[:8])
+}
+
+func (z *ioEncWriter) writeb(bs []byte) {
+	if len(bs) == 0 {
+		return
+	}
+	n, err := z.w.Write(bs)
+	if err != nil {
+		panic(err)
+	}
+	if n != len(bs) {
+		encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n)
+	}
+}
+
+func (z *ioEncWriter) writestr(s string) {
+	n, err := z.w.WriteString(s)
+	if err != nil {
+		panic(err)
+	}
+	if n != len(s) {
+		encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n)
+	}
+}
+
+func (z *ioEncWriter) writen1(b byte) {
+	if err := z.w.WriteByte(b); err != nil {
+		panic(err)
+	}
+}
+
+func (z *ioEncWriter) writen2(b1 byte, b2 byte) {
+	z.writen1(b1)
+	z.writen1(b2)
+}
+
+func (z *ioEncWriter) atEndOfEncode() {}
+
+// ----------------------------------------
+
+// bytesEncWriter implements encWriter and can write to an byte slice.
+// It is used by Marshal function.
+type bytesEncWriter struct {
+	b   []byte
+	c   int     // cursor
+	out *[]byte // write out on atEndOfEncode
+}
+
+func (z *bytesEncWriter) writeUint16(v uint16) {
+	c := z.grow(2)
+	z.b[c] = byte(v >> 8)
+	z.b[c+1] = byte(v)
+}
+
+func (z *bytesEncWriter) writeUint32(v uint32) {
+	c := z.grow(4)
+	z.b[c] = byte(v >> 24)
+	z.b[c+1] = byte(v >> 16)
+	z.b[c+2] = byte(v >> 8)
+	z.b[c+3] = byte(v)
+}
+
+func (z *bytesEncWriter) writeUint64(v uint64) {
+	c := z.grow(8)
+	z.b[c] = byte(v >> 56)
+	z.b[c+1] = byte(v >> 48)
+	z.b[c+2] = byte(v >> 40)
+	z.b[c+3] = byte(v >> 32)
+	z.b[c+4] = byte(v >> 24)
+	z.b[c+5] = byte(v >> 16)
+	z.b[c+6] = byte(v >> 8)
+	z.b[c+7] = byte(v)
+}
+
+func (z *bytesEncWriter) writeb(s []byte) {
+	if len(s) == 0 {
+		return
+	}
+	c := z.grow(len(s))
+	copy(z.b[c:], s)
+}
+
+func (z *bytesEncWriter) writestr(s string) {
+	c := z.grow(len(s))
+	copy(z.b[c:], s)
+}
+
+func (z *bytesEncWriter) writen1(b1 byte) {
+	c := z.grow(1)
+	z.b[c] = b1
+}
+
+func (z *bytesEncWriter) writen2(b1 byte, b2 byte) {
+	c := z.grow(2)
+	z.b[c] = b1
+	z.b[c+1] = b2
+}
+
+func (z *bytesEncWriter) atEndOfEncode() {
+	*(z.out) = z.b[:z.c]
+}
+
+func (z *bytesEncWriter) grow(n int) (oldcursor int) {
+	oldcursor = z.c
+	z.c = oldcursor + n
+	if z.c > cap(z.b) {
+		// Tried using appendslice logic: (if cap < 1024, *2, else *1.25).
+		// However, it was too expensive, causing too many iterations of copy.
+		// Using bytes.Buffer model was much better (2*cap + n)
+		bs := make([]byte, 2*cap(z.b)+n)
+		copy(bs, z.b[:oldcursor])
+		z.b = bs
+	} else if z.c > len(z.b) {
+		z.b = z.b[:cap(z.b)]
+	}
+	return
+}
+
+// ---------------------------------------------
+
+type encFnInfo struct {
+	ti    *typeInfo
+	e     *Encoder
+	ee    encDriver
+	xfFn  func(reflect.Value) ([]byte, error)
+	xfTag byte
+}
+
+func (f *encFnInfo) builtin(rv reflect.Value) {
+	f.ee.encodeBuiltin(f.ti.rtid, rv.Interface())
+}
+
+func (f *encFnInfo) rawExt(rv reflect.Value) {
+	f.e.encRawExt(rv.Interface().(RawExt))
+}
+
+func (f *encFnInfo) ext(rv reflect.Value) {
+	bs, fnerr := f.xfFn(rv)
+	if fnerr != nil {
+		panic(fnerr)
+	}
+	if bs == nil {
+		f.ee.encodeNil()
+		return
+	}
+	if f.e.hh.writeExt() {
+		f.ee.encodeExtPreamble(f.xfTag, len(bs))
+		f.e.w.writeb(bs)
+	} else {
+		f.ee.encodeStringBytes(c_RAW, bs)
+	}
+
+}
+
+func (f *encFnInfo) binaryMarshal(rv reflect.Value) {
+	var bm binaryMarshaler
+	if f.ti.mIndir == 0 {
+		bm = rv.Interface().(binaryMarshaler)
+	} else if f.ti.mIndir == -1 {
+		bm = rv.Addr().Interface().(binaryMarshaler)
+	} else {
+		for j, k := int8(0), f.ti.mIndir; j < k; j++ {
+			if rv.IsNil() {
+				f.ee.encodeNil()
+				return
+			}
+			rv = rv.Elem()
+		}
+		bm = rv.Interface().(binaryMarshaler)
+	}
+	// debugf(">>>> binaryMarshaler: %T", rv.Interface())
+	bs, fnerr := bm.MarshalBinary()
+	if fnerr != nil {
+		panic(fnerr)
+	}
+	if bs == nil {
+		f.ee.encodeNil()
+	} else {
+		f.ee.encodeStringBytes(c_RAW, bs)
+	}
+}
+
+func (f *encFnInfo) kBool(rv reflect.Value) {
+	f.ee.encodeBool(rv.Bool())
+}
+
+func (f *encFnInfo) kString(rv reflect.Value) {
+	f.ee.encodeString(c_UTF8, rv.String())
+}
+
+func (f *encFnInfo) kFloat64(rv reflect.Value) {
+	f.ee.encodeFloat64(rv.Float())
+}
+
+func (f *encFnInfo) kFloat32(rv reflect.Value) {
+	f.ee.encodeFloat32(float32(rv.Float()))
+}
+
+func (f *encFnInfo) kInt(rv reflect.Value) {
+	f.ee.encodeInt(rv.Int())
+}
+
+func (f *encFnInfo) kUint(rv reflect.Value) {
+	f.ee.encodeUint(rv.Uint())
+}
+
+func (f *encFnInfo) kInvalid(rv reflect.Value) {
+	f.ee.encodeNil()
+}
+
+func (f *encFnInfo) kErr(rv reflect.Value) {
+	encErr("Unsupported kind: %s, for: %#v", rv.Kind(), rv)
+}
+
+func (f *encFnInfo) kSlice(rv reflect.Value) {
+	if rv.IsNil() {
+		f.ee.encodeNil()
+		return
+	}
+
+	if shortCircuitReflectToFastPath {
+		switch f.ti.rtid {
+		case intfSliceTypId:
+			f.e.encSliceIntf(rv.Interface().([]interface{}))
+			return
+		case strSliceTypId:
+			f.e.encSliceStr(rv.Interface().([]string))
+			return
+		case uint64SliceTypId:
+			f.e.encSliceUint64(rv.Interface().([]uint64))
+			return
+		case int64SliceTypId:
+			f.e.encSliceInt64(rv.Interface().([]int64))
+			return
+		}
+	}
+
+	// If in this method, then there was no extension function defined.
+	// So it's okay to treat as []byte.
+	if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 {
+		f.ee.encodeStringBytes(c_RAW, rv.Bytes())
+		return
+	}
+
+	l := rv.Len()
+	if f.ti.mbs {
+		if l%2 == 1 {
+			encErr("mapBySlice: invalid length (must be divisible by 2): %v", l)
+		}
+		f.ee.encodeMapPreamble(l / 2)
+	} else {
+		f.ee.encodeArrayPreamble(l)
+	}
+	if l == 0 {
+		return
+	}
+	for j := 0; j < l; j++ {
+		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
+		f.e.encodeValue(rv.Index(j))
+	}
+}
+
+func (f *encFnInfo) kArray(rv reflect.Value) {
+	// We cannot share kSlice method, because the array may be non-addressable.
+	// E.g. type struct S{B [2]byte}; Encode(S{}) will bomb on "panic: slice of unaddressable array".
+	// So we have to duplicate the functionality here.
+	// f.e.encodeValue(rv.Slice(0, rv.Len()))
+	// f.kSlice(rv.Slice(0, rv.Len()))
+
+	l := rv.Len()
+	// Handle an array of bytes specially (in line with what is done for slices)
+	if f.ti.rt.Elem().Kind() == reflect.Uint8 {
+		if l == 0 {
+			f.ee.encodeStringBytes(c_RAW, nil)
+			return
+		}
+		var bs []byte
+		if rv.CanAddr() {
+			bs = rv.Slice(0, l).Bytes()
+		} else {
+			bs = make([]byte, l)
+			for i := 0; i < l; i++ {
+				bs[i] = byte(rv.Index(i).Uint())
+			}
+		}
+		f.ee.encodeStringBytes(c_RAW, bs)
+		return
+	}
+
+	if f.ti.mbs {
+		if l%2 == 1 {
+			encErr("mapBySlice: invalid length (must be divisible by 2): %v", l)
+		}
+		f.ee.encodeMapPreamble(l / 2)
+	} else {
+		f.ee.encodeArrayPreamble(l)
+	}
+	if l == 0 {
+		return
+	}
+	for j := 0; j < l; j++ {
+		// TODO: Consider perf implication of encoding odd index values as symbols if type is string
+		f.e.encodeValue(rv.Index(j))
+	}
+}
+
+func (f *encFnInfo) kStruct(rv reflect.Value) {
+	fti := f.ti
+	newlen := len(fti.sfi)
+	rvals := make([]reflect.Value, newlen)
+	var encnames []string
+	e := f.e
+	tisfi := fti.sfip
+	toMap := !(fti.toArray || e.h.StructToArray)
+	// if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct)
+	if toMap {
+		tisfi = fti.sfi
+		encnames = make([]string, newlen)
+	}
+	newlen = 0
+	for _, si := range tisfi {
+		if si.i != -1 {
+			rvals[newlen] = rv.Field(int(si.i))
+		} else {
+			rvals[newlen] = rv.FieldByIndex(si.is)
+		}
+		if toMap {
+			if si.omitEmpty && isEmptyValue(rvals[newlen]) {
+				continue
+			}
+			encnames[newlen] = si.encName
+		} else {
+			if si.omitEmpty && isEmptyValue(rvals[newlen]) {
+				rvals[newlen] = reflect.Value{} //encode as nil
+			}
+		}
+		newlen++
+	}
+
+	// debugf(">>>> kStruct: newlen: %v", newlen)
+	if toMap {
+		ee := f.ee //don't dereference everytime
+		ee.encodeMapPreamble(newlen)
+		// asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+		asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0
+		for j := 0; j < newlen; j++ {
+			if asSymbols {
+				ee.encodeSymbol(encnames[j])
+			} else {
+				ee.encodeString(c_UTF8, encnames[j])
+			}
+			e.encodeValue(rvals[j])
+		}
+	} else {
+		f.ee.encodeArrayPreamble(newlen)
+		for j := 0; j < newlen; j++ {
+			e.encodeValue(rvals[j])
+		}
+	}
+}
+
+// func (f *encFnInfo) kPtr(rv reflect.Value) {
+// 	debugf(">>>>>>> ??? encode kPtr called - shouldn't get called")
+// 	if rv.IsNil() {
+// 		f.ee.encodeNil()
+// 		return
+// 	}
+// 	f.e.encodeValue(rv.Elem())
+// }
+
+func (f *encFnInfo) kInterface(rv reflect.Value) {
+	if rv.IsNil() {
+		f.ee.encodeNil()
+		return
+	}
+	f.e.encodeValue(rv.Elem())
+}
+
+func (f *encFnInfo) kMap(rv reflect.Value) {
+	if rv.IsNil() {
+		f.ee.encodeNil()
+		return
+	}
+
+	if shortCircuitReflectToFastPath {
+		switch f.ti.rtid {
+		case mapIntfIntfTypId:
+			f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{}))
+			return
+		case mapStrIntfTypId:
+			f.e.encMapStrIntf(rv.Interface().(map[string]interface{}))
+			return
+		case mapStrStrTypId:
+			f.e.encMapStrStr(rv.Interface().(map[string]string))
+			return
+		case mapInt64IntfTypId:
+			f.e.encMapInt64Intf(rv.Interface().(map[int64]interface{}))
+			return
+		case mapUint64IntfTypId:
+			f.e.encMapUint64Intf(rv.Interface().(map[uint64]interface{}))
+			return
+		}
+	}
+
+	l := rv.Len()
+	f.ee.encodeMapPreamble(l)
+	if l == 0 {
+		return
+	}
+	// keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String
+	keyTypeIsString := f.ti.rt.Key() == stringTyp
+	var asSymbols bool
+	if keyTypeIsString {
+		asSymbols = f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	}
+	mks := rv.MapKeys()
+	// for j, lmks := 0, len(mks); j < lmks; j++ {
+	for j := range mks {
+		if keyTypeIsString {
+			if asSymbols {
+				f.ee.encodeSymbol(mks[j].String())
+			} else {
+				f.ee.encodeString(c_UTF8, mks[j].String())
+			}
+		} else {
+			f.e.encodeValue(mks[j])
+		}
+		f.e.encodeValue(rv.MapIndex(mks[j]))
+	}
+
+}
+
+// --------------------------------------------------
+
+// encFn encapsulates the captured variables and the encode function.
+// This way, we only do some calculations one times, and pass to the
+// code block that should be called (encapsulated in a function)
+// instead of executing the checks every time.
+type encFn struct {
+	i *encFnInfo
+	f func(*encFnInfo, reflect.Value)
+}
+
+// --------------------------------------------------
+
+// An Encoder writes an object to an output stream in the codec format.
+type Encoder struct {
+	w  encWriter
+	e  encDriver
+	h  *BasicHandle
+	hh Handle
+	f  map[uintptr]encFn
+	x  []uintptr
+	s  []encFn
+}
+
+// NewEncoder returns an Encoder for encoding into an io.Writer.
+//
+// For efficiency, Users are encouraged to pass in a memory buffered writer
+// (eg bufio.Writer, bytes.Buffer).
+func NewEncoder(w io.Writer, h Handle) *Encoder {
+	ww, ok := w.(ioEncWriterWriter)
+	if !ok {
+		sww := simpleIoEncWriterWriter{w: w}
+		sww.bw, _ = w.(io.ByteWriter)
+		sww.sw, _ = w.(ioEncStringWriter)
+		ww = &sww
+		//ww = bufio.NewWriterSize(w, defEncByteBufSize)
+	}
+	z := ioEncWriter{
+		w: ww,
+	}
+	return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)}
+}
+
+// NewEncoderBytes returns an encoder for encoding directly and efficiently
+// into a byte slice, using zero-copying to temporary slices.
+//
+// It will potentially replace the output byte slice pointed to.
+// After encoding, the out parameter contains the encoded contents.
+func NewEncoderBytes(out *[]byte, h Handle) *Encoder {
+	in := *out
+	if in == nil {
+		in = make([]byte, defEncByteBufSize)
+	}
+	z := bytesEncWriter{
+		b:   in,
+		out: out,
+	}
+	return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)}
+}
+
+// Encode writes an object into a stream in the codec format.
+//
+// Encoding can be configured via the "codec" struct tag for the fields.
+//
+// The "codec" key in struct field's tag value is the key name,
+// followed by an optional comma and options.
+//
+// To set an option on all fields (e.g. omitempty on all fields), you
+// can create a field called _struct, and set flags on it.
+//
+// Struct values "usually" encode as maps. Each exported struct field is encoded unless:
+//    - the field's codec tag is "-", OR
+//    - the field is empty and its codec tag specifies the "omitempty" option.
+//
+// When encoding as a map, the first string in the tag (before the comma)
+// is the map key string to use when encoding.
+//
+// However, struct values may encode as arrays. This happens when:
+//    - StructToArray Encode option is set, OR
+//    - the codec tag on the _struct field sets the "toarray" option
+//
+// Values with types that implement MapBySlice are encoded as stream maps.
+//
+// The empty values (for omitempty option) are false, 0, any nil pointer
+// or interface value, and any array, slice, map, or string of length zero.
+//
+// Anonymous fields are encoded inline if no struct tag is present.
+// Else they are encoded as regular fields.
+//
+// Examples:
+//
+//      type MyStruct struct {
+//          _struct bool    `codec:",omitempty"`   //set omitempty for every field
+//          Field1 string   `codec:"-"`            //skip this field
+//          Field2 int      `codec:"myName"`       //Use key "myName" in encode stream
+//          Field3 int32    `codec:",omitempty"`   //use key "Field3". Omit if empty.
+//          Field4 bool     `codec:"f4,omitempty"` //use key "f4". Omit if empty.
+//          ...
+//      }
+//
+//      type MyStruct struct {
+//          _struct bool    `codec:",omitempty,toarray"`   //set omitempty for every field
+//                                                         //and encode struct as an array
+//      }
+//
+// The mode of encoding is based on the type of the value. When a value is seen:
+//   - If an extension is registered for it, call that extension function
+//   - If it implements BinaryMarshaler, call its MarshalBinary() (data []byte, err error)
+//   - Else encode it based on its reflect.Kind
+//
+// Note that struct field names and keys in map[string]XXX will be treated as symbols.
+// Some formats support symbols (e.g. binc) and will properly encode the string
+// only once in the stream, and use a tag to refer to it thereafter.
+func (e *Encoder) Encode(v interface{}) (err error) {
+	defer panicToErr(&err)
+	e.encode(v)
+	e.w.atEndOfEncode()
+	return
+}
+
+func (e *Encoder) encode(iv interface{}) {
+	switch v := iv.(type) {
+	case nil:
+		e.e.encodeNil()
+
+	case reflect.Value:
+		e.encodeValue(v)
+
+	case string:
+		e.e.encodeString(c_UTF8, v)
+	case bool:
+		e.e.encodeBool(v)
+	case int:
+		e.e.encodeInt(int64(v))
+	case int8:
+		e.e.encodeInt(int64(v))
+	case int16:
+		e.e.encodeInt(int64(v))
+	case int32:
+		e.e.encodeInt(int64(v))
+	case int64:
+		e.e.encodeInt(v)
+	case uint:
+		e.e.encodeUint(uint64(v))
+	case uint8:
+		e.e.encodeUint(uint64(v))
+	case uint16:
+		e.e.encodeUint(uint64(v))
+	case uint32:
+		e.e.encodeUint(uint64(v))
+	case uint64:
+		e.e.encodeUint(v)
+	case float32:
+		e.e.encodeFloat32(v)
+	case float64:
+		e.e.encodeFloat64(v)
+
+	case []interface{}:
+		e.encSliceIntf(v)
+	case []string:
+		e.encSliceStr(v)
+	case []int64:
+		e.encSliceInt64(v)
+	case []uint64:
+		e.encSliceUint64(v)
+	case []uint8:
+		e.e.encodeStringBytes(c_RAW, v)
+
+	case map[interface{}]interface{}:
+		e.encMapIntfIntf(v)
+	case map[string]interface{}:
+		e.encMapStrIntf(v)
+	case map[string]string:
+		e.encMapStrStr(v)
+	case map[int64]interface{}:
+		e.encMapInt64Intf(v)
+	case map[uint64]interface{}:
+		e.encMapUint64Intf(v)
+
+	case *string:
+		e.e.encodeString(c_UTF8, *v)
+	case *bool:
+		e.e.encodeBool(*v)
+	case *int:
+		e.e.encodeInt(int64(*v))
+	case *int8:
+		e.e.encodeInt(int64(*v))
+	case *int16:
+		e.e.encodeInt(int64(*v))
+	case *int32:
+		e.e.encodeInt(int64(*v))
+	case *int64:
+		e.e.encodeInt(*v)
+	case *uint:
+		e.e.encodeUint(uint64(*v))
+	case *uint8:
+		e.e.encodeUint(uint64(*v))
+	case *uint16:
+		e.e.encodeUint(uint64(*v))
+	case *uint32:
+		e.e.encodeUint(uint64(*v))
+	case *uint64:
+		e.e.encodeUint(*v)
+	case *float32:
+		e.e.encodeFloat32(*v)
+	case *float64:
+		e.e.encodeFloat64(*v)
+
+	case *[]interface{}:
+		e.encSliceIntf(*v)
+	case *[]string:
+		e.encSliceStr(*v)
+	case *[]int64:
+		e.encSliceInt64(*v)
+	case *[]uint64:
+		e.encSliceUint64(*v)
+	case *[]uint8:
+		e.e.encodeStringBytes(c_RAW, *v)
+
+	case *map[interface{}]interface{}:
+		e.encMapIntfIntf(*v)
+	case *map[string]interface{}:
+		e.encMapStrIntf(*v)
+	case *map[string]string:
+		e.encMapStrStr(*v)
+	case *map[int64]interface{}:
+		e.encMapInt64Intf(*v)
+	case *map[uint64]interface{}:
+		e.encMapUint64Intf(*v)
+
+	default:
+		e.encodeValue(reflect.ValueOf(iv))
+	}
+}
+
+func (e *Encoder) encodeValue(rv reflect.Value) {
+	for rv.Kind() == reflect.Ptr {
+		if rv.IsNil() {
+			e.e.encodeNil()
+			return
+		}
+		rv = rv.Elem()
+	}
+
+	rt := rv.Type()
+	rtid := reflect.ValueOf(rt).Pointer()
+
+	// if e.f == nil && e.s == nil { debugf("---->Creating new enc f map for type: %v\n", rt) }
+	var fn encFn
+	var ok bool
+	if useMapForCodecCache {
+		fn, ok = e.f[rtid]
+	} else {
+		for i, v := range e.x {
+			if v == rtid {
+				fn, ok = e.s[i], true
+				break
+			}
+		}
+	}
+	if !ok {
+		// debugf("\tCreating new enc fn for type: %v\n", rt)
+		fi := encFnInfo{ti: getTypeInfo(rtid, rt), e: e, ee: e.e}
+		fn.i = &fi
+		if rtid == rawExtTypId {
+			fn.f = (*encFnInfo).rawExt
+		} else if e.e.isBuiltinType(rtid) {
+			fn.f = (*encFnInfo).builtin
+		} else if xfTag, xfFn := e.h.getEncodeExt(rtid); xfFn != nil {
+			fi.xfTag, fi.xfFn = xfTag, xfFn
+			fn.f = (*encFnInfo).ext
+		} else if supportBinaryMarshal && fi.ti.m {
+			fn.f = (*encFnInfo).binaryMarshal
+		} else {
+			switch rk := rt.Kind(); rk {
+			case reflect.Bool:
+				fn.f = (*encFnInfo).kBool
+			case reflect.String:
+				fn.f = (*encFnInfo).kString
+			case reflect.Float64:
+				fn.f = (*encFnInfo).kFloat64
+			case reflect.Float32:
+				fn.f = (*encFnInfo).kFloat32
+			case reflect.Int, reflect.Int8, reflect.Int64, reflect.Int32, reflect.Int16:
+				fn.f = (*encFnInfo).kInt
+			case reflect.Uint8, reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16:
+				fn.f = (*encFnInfo).kUint
+			case reflect.Invalid:
+				fn.f = (*encFnInfo).kInvalid
+			case reflect.Slice:
+				fn.f = (*encFnInfo).kSlice
+			case reflect.Array:
+				fn.f = (*encFnInfo).kArray
+			case reflect.Struct:
+				fn.f = (*encFnInfo).kStruct
+			// case reflect.Ptr:
+			// 	fn.f = (*encFnInfo).kPtr
+			case reflect.Interface:
+				fn.f = (*encFnInfo).kInterface
+			case reflect.Map:
+				fn.f = (*encFnInfo).kMap
+			default:
+				fn.f = (*encFnInfo).kErr
+			}
+		}
+		if useMapForCodecCache {
+			if e.f == nil {
+				e.f = make(map[uintptr]encFn, 16)
+			}
+			e.f[rtid] = fn
+		} else {
+			e.s = append(e.s, fn)
+			e.x = append(e.x, rtid)
+		}
+	}
+
+	fn.f(fn.i, rv)
+
+}
+
+func (e *Encoder) encRawExt(re RawExt) {
+	if re.Data == nil {
+		e.e.encodeNil()
+		return
+	}
+	if e.hh.writeExt() {
+		e.e.encodeExtPreamble(re.Tag, len(re.Data))
+		e.w.writeb(re.Data)
+	} else {
+		e.e.encodeStringBytes(c_RAW, re.Data)
+	}
+}
+
+// ---------------------------------------------
+// short circuit functions for common maps and slices
+
+func (e *Encoder) encSliceIntf(v []interface{}) {
+	e.e.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		e.encode(v2)
+	}
+}
+
+func (e *Encoder) encSliceStr(v []string) {
+	e.e.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		e.e.encodeString(c_UTF8, v2)
+	}
+}
+
+func (e *Encoder) encSliceInt64(v []int64) {
+	e.e.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		e.e.encodeInt(v2)
+	}
+}
+
+func (e *Encoder) encSliceUint64(v []uint64) {
+	e.e.encodeArrayPreamble(len(v))
+	for _, v2 := range v {
+		e.e.encodeUint(v2)
+	}
+}
+
+func (e *Encoder) encMapStrStr(v map[string]string) {
+	e.e.encodeMapPreamble(len(v))
+	asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	for k2, v2 := range v {
+		if asSymbols {
+			e.e.encodeSymbol(k2)
+		} else {
+			e.e.encodeString(c_UTF8, k2)
+		}
+		e.e.encodeString(c_UTF8, v2)
+	}
+}
+
+func (e *Encoder) encMapStrIntf(v map[string]interface{}) {
+	e.e.encodeMapPreamble(len(v))
+	asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
+	for k2, v2 := range v {
+		if asSymbols {
+			e.e.encodeSymbol(k2)
+		} else {
+			e.e.encodeString(c_UTF8, k2)
+		}
+		e.encode(v2)
+	}
+}
+
+func (e *Encoder) encMapInt64Intf(v map[int64]interface{}) {
+	e.e.encodeMapPreamble(len(v))
+	for k2, v2 := range v {
+		e.e.encodeInt(k2)
+		e.encode(v2)
+	}
+}
+
+func (e *Encoder) encMapUint64Intf(v map[uint64]interface{}) {
+	e.e.encodeMapPreamble(len(v))
+	for k2, v2 := range v {
+		e.e.encodeUint(uint64(k2))
+		e.encode(v2)
+	}
+}
+
+func (e *Encoder) encMapIntfIntf(v map[interface{}]interface{}) {
+	e.e.encodeMapPreamble(len(v))
+	for k2, v2 := range v {
+		e.encode(k2)
+		e.encode(v2)
+	}
+}
+
+// ----------------------------------------
+
+func encErr(format string, params ...interface{}) {
+	doPanic(msgTagEnc, format, params...)
+}

+ 75 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/ext_dep_test.go

@@ -0,0 +1,75 @@
+// //+build ignore
+
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// This file includes benchmarks which have dependencies on 3rdparty
+// packages (bson and vmihailenco/msgpack) which must be installed locally.
+//
+// To run the benchmarks including these 3rdparty packages, first
+//   - Uncomment first line in this file (put // // in front of it)
+//   - Get those packages:
+//       go get github.com/vmihailenco/msgpack
+//       go get labix.org/v2/mgo/bson
+//   - Run:
+//       go test -bi -bench=.
+
+import (
+	"testing"
+
+	vmsgpack "github.com/vmihailenco/msgpack"
+	"labix.org/v2/mgo/bson"
+)
+
+func init() {
+	benchCheckers = append(benchCheckers,
+		benchChecker{"v-msgpack", fnVMsgpackEncodeFn, fnVMsgpackDecodeFn},
+		benchChecker{"bson", fnBsonEncodeFn, fnBsonDecodeFn},
+	)
+}
+
+func fnVMsgpackEncodeFn(ts interface{}) ([]byte, error) {
+	return vmsgpack.Marshal(ts)
+}
+
+func fnVMsgpackDecodeFn(buf []byte, ts interface{}) error {
+	return vmsgpack.Unmarshal(buf, ts)
+}
+
+func fnBsonEncodeFn(ts interface{}) ([]byte, error) {
+	return bson.Marshal(ts)
+}
+
+func fnBsonDecodeFn(buf []byte, ts interface{}) error {
+	return bson.Unmarshal(buf, ts)
+}
+
+func Benchmark__Bson_______Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "bson", benchTs, fnBsonEncodeFn)
+}
+
+func Benchmark__Bson_______Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "bson", benchTs, fnBsonEncodeFn, fnBsonDecodeFn, fnBenchNewTs)
+}
+
+func Benchmark__VMsgpack___Encode(b *testing.B) {
+	fnBenchmarkEncode(b, "v-msgpack", benchTs, fnVMsgpackEncodeFn)
+}
+
+func Benchmark__VMsgpack___Decode(b *testing.B) {
+	fnBenchmarkDecode(b, "v-msgpack", benchTs, fnVMsgpackEncodeFn, fnVMsgpackDecodeFn, fnBenchNewTs)
+}
+
+func TestMsgpackPythonGenStreams(t *testing.T) {
+	doTestMsgpackPythonGenStreams(t)
+}
+
+func TestMsgpackRpcSpecGoClientToPythonSvc(t *testing.T) {
+	doTestMsgpackRpcSpecGoClientToPythonSvc(t)
+}
+
+func TestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) {
+	doTestMsgpackRpcSpecPythonClientToGoSvc(t)
+}

+ 589 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/helper.go

@@ -0,0 +1,589 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// Contains code shared by both encode and decode.
+
+import (
+	"encoding/binary"
+	"fmt"
+	"math"
+	"reflect"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+	"unicode"
+	"unicode/utf8"
+)
+
+const (
+	structTagName = "codec"
+
+	// Support
+	//    encoding.BinaryMarshaler: MarshalBinary() (data []byte, err error)
+	//    encoding.BinaryUnmarshaler: UnmarshalBinary(data []byte) error
+	// This constant flag will enable or disable it.
+	supportBinaryMarshal = true
+
+	// Each Encoder or Decoder uses a cache of functions based on conditionals,
+	// so that the conditionals are not run every time.
+	//
+	// Either a map or a slice is used to keep track of the functions.
+	// The map is more natural, but has a higher cost than a slice/array.
+	// This flag (useMapForCodecCache) controls which is used.
+	useMapForCodecCache = false
+
+	// For some common container types, we can short-circuit an elaborate
+	// reflection dance and call encode/decode directly.
+	// The currently supported types are:
+	//    - slices of strings, or id's (int64,uint64) or interfaces.
+	//    - maps of str->str, str->intf, id(int64,uint64)->intf, intf->intf
+	shortCircuitReflectToFastPath = true
+
+	// for debugging, set this to false, to catch panic traces.
+	// Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic.
+	recoverPanicToErr = true
+)
+
+type charEncoding uint8
+
+const (
+	c_RAW charEncoding = iota
+	c_UTF8
+	c_UTF16LE
+	c_UTF16BE
+	c_UTF32LE
+	c_UTF32BE
+)
+
+// valueType is the stream type
+type valueType uint8
+
+const (
+	valueTypeUnset valueType = iota
+	valueTypeNil
+	valueTypeInt
+	valueTypeUint
+	valueTypeFloat
+	valueTypeBool
+	valueTypeString
+	valueTypeSymbol
+	valueTypeBytes
+	valueTypeMap
+	valueTypeArray
+	valueTypeTimestamp
+	valueTypeExt
+
+	valueTypeInvalid = 0xff
+)
+
+var (
+	bigen               = binary.BigEndian
+	structInfoFieldName = "_struct"
+
+	cachedTypeInfo      = make(map[uintptr]*typeInfo, 4)
+	cachedTypeInfoMutex sync.RWMutex
+
+	intfSliceTyp = reflect.TypeOf([]interface{}(nil))
+	intfTyp      = intfSliceTyp.Elem()
+
+	strSliceTyp     = reflect.TypeOf([]string(nil))
+	boolSliceTyp    = reflect.TypeOf([]bool(nil))
+	uintSliceTyp    = reflect.TypeOf([]uint(nil))
+	uint8SliceTyp   = reflect.TypeOf([]uint8(nil))
+	uint16SliceTyp  = reflect.TypeOf([]uint16(nil))
+	uint32SliceTyp  = reflect.TypeOf([]uint32(nil))
+	uint64SliceTyp  = reflect.TypeOf([]uint64(nil))
+	intSliceTyp     = reflect.TypeOf([]int(nil))
+	int8SliceTyp    = reflect.TypeOf([]int8(nil))
+	int16SliceTyp   = reflect.TypeOf([]int16(nil))
+	int32SliceTyp   = reflect.TypeOf([]int32(nil))
+	int64SliceTyp   = reflect.TypeOf([]int64(nil))
+	float32SliceTyp = reflect.TypeOf([]float32(nil))
+	float64SliceTyp = reflect.TypeOf([]float64(nil))
+
+	mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil))
+	mapStrIntfTyp  = reflect.TypeOf(map[string]interface{}(nil))
+	mapStrStrTyp   = reflect.TypeOf(map[string]string(nil))
+
+	mapIntIntfTyp    = reflect.TypeOf(map[int]interface{}(nil))
+	mapInt64IntfTyp  = reflect.TypeOf(map[int64]interface{}(nil))
+	mapUintIntfTyp   = reflect.TypeOf(map[uint]interface{}(nil))
+	mapUint64IntfTyp = reflect.TypeOf(map[uint64]interface{}(nil))
+
+	stringTyp = reflect.TypeOf("")
+	timeTyp   = reflect.TypeOf(time.Time{})
+	rawExtTyp = reflect.TypeOf(RawExt{})
+
+	mapBySliceTyp        = reflect.TypeOf((*MapBySlice)(nil)).Elem()
+	binaryMarshalerTyp   = reflect.TypeOf((*binaryMarshaler)(nil)).Elem()
+	binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(nil)).Elem()
+
+	rawExtTypId = reflect.ValueOf(rawExtTyp).Pointer()
+	intfTypId   = reflect.ValueOf(intfTyp).Pointer()
+	timeTypId   = reflect.ValueOf(timeTyp).Pointer()
+
+	intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer()
+	strSliceTypId  = reflect.ValueOf(strSliceTyp).Pointer()
+
+	boolSliceTypId    = reflect.ValueOf(boolSliceTyp).Pointer()
+	uintSliceTypId    = reflect.ValueOf(uintSliceTyp).Pointer()
+	uint8SliceTypId   = reflect.ValueOf(uint8SliceTyp).Pointer()
+	uint16SliceTypId  = reflect.ValueOf(uint16SliceTyp).Pointer()
+	uint32SliceTypId  = reflect.ValueOf(uint32SliceTyp).Pointer()
+	uint64SliceTypId  = reflect.ValueOf(uint64SliceTyp).Pointer()
+	intSliceTypId     = reflect.ValueOf(intSliceTyp).Pointer()
+	int8SliceTypId    = reflect.ValueOf(int8SliceTyp).Pointer()
+	int16SliceTypId   = reflect.ValueOf(int16SliceTyp).Pointer()
+	int32SliceTypId   = reflect.ValueOf(int32SliceTyp).Pointer()
+	int64SliceTypId   = reflect.ValueOf(int64SliceTyp).Pointer()
+	float32SliceTypId = reflect.ValueOf(float32SliceTyp).Pointer()
+	float64SliceTypId = reflect.ValueOf(float64SliceTyp).Pointer()
+
+	mapStrStrTypId     = reflect.ValueOf(mapStrStrTyp).Pointer()
+	mapIntfIntfTypId   = reflect.ValueOf(mapIntfIntfTyp).Pointer()
+	mapStrIntfTypId    = reflect.ValueOf(mapStrIntfTyp).Pointer()
+	mapIntIntfTypId    = reflect.ValueOf(mapIntIntfTyp).Pointer()
+	mapInt64IntfTypId  = reflect.ValueOf(mapInt64IntfTyp).Pointer()
+	mapUintIntfTypId   = reflect.ValueOf(mapUintIntfTyp).Pointer()
+	mapUint64IntfTypId = reflect.ValueOf(mapUint64IntfTyp).Pointer()
+	// Id = reflect.ValueOf().Pointer()
+	// mapBySliceTypId  = reflect.ValueOf(mapBySliceTyp).Pointer()
+
+	binaryMarshalerTypId   = reflect.ValueOf(binaryMarshalerTyp).Pointer()
+	binaryUnmarshalerTypId = reflect.ValueOf(binaryUnmarshalerTyp).Pointer()
+
+	intBitsize  uint8 = uint8(reflect.TypeOf(int(0)).Bits())
+	uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits())
+
+	bsAll0x00 = []byte{0, 0, 0, 0, 0, 0, 0, 0}
+	bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+)
+
+type binaryUnmarshaler interface {
+	UnmarshalBinary(data []byte) error
+}
+
+type binaryMarshaler interface {
+	MarshalBinary() (data []byte, err error)
+}
+
+// MapBySlice represents a slice which should be encoded as a map in the stream.
+// The slice contains a sequence of key-value pairs.
+type MapBySlice interface {
+	MapBySlice()
+}
+
+// WARNING: DO NOT USE DIRECTLY. EXPORTED FOR GODOC BENEFIT. WILL BE REMOVED.
+//
+// BasicHandle encapsulates the common options and extension functions.
+type BasicHandle struct {
+	extHandle
+	EncodeOptions
+	DecodeOptions
+}
+
+// Handle is the interface for a specific encoding format.
+//
+// Typically, a Handle is pre-configured before first time use,
+// and not modified while in use. Such a pre-configured Handle
+// is safe for concurrent access.
+type Handle interface {
+	writeExt() bool
+	getBasicHandle() *BasicHandle
+	newEncDriver(w encWriter) encDriver
+	newDecDriver(r decReader) decDriver
+}
+
+// RawExt represents raw unprocessed extension data.
+type RawExt struct {
+	Tag  byte
+	Data []byte
+}
+
+type extTypeTagFn struct {
+	rtid  uintptr
+	rt    reflect.Type
+	tag   byte
+	encFn func(reflect.Value) ([]byte, error)
+	decFn func(reflect.Value, []byte) error
+}
+
+type extHandle []*extTypeTagFn
+
+// AddExt registers an encode and decode function for a reflect.Type.
+// Note that the type must be a named type, and specifically not
+// a pointer or Interface. An error is returned if that is not honored.
+//
+// To Deregister an ext, call AddExt with 0 tag, nil encfn and nil decfn.
+func (o *extHandle) AddExt(
+	rt reflect.Type,
+	tag byte,
+	encfn func(reflect.Value) ([]byte, error),
+	decfn func(reflect.Value, []byte) error,
+) (err error) {
+	// o is a pointer, because we may need to initialize it
+	if rt.PkgPath() == "" || rt.Kind() == reflect.Interface {
+		err = fmt.Errorf("codec.Handle.AddExt: Takes named type, especially not a pointer or interface: %T",
+			reflect.Zero(rt).Interface())
+		return
+	}
+
+	// o cannot be nil, since it is always embedded in a Handle.
+	// if nil, let it panic.
+	// if o == nil {
+	// 	err = errors.New("codec.Handle.AddExt: extHandle cannot be a nil pointer.")
+	// 	return
+	// }
+
+	rtid := reflect.ValueOf(rt).Pointer()
+	for _, v := range *o {
+		if v.rtid == rtid {
+			v.tag, v.encFn, v.decFn = tag, encfn, decfn
+			return
+		}
+	}
+
+	*o = append(*o, &extTypeTagFn{rtid, rt, tag, encfn, decfn})
+	return
+}
+
+func (o extHandle) getExt(rtid uintptr) *extTypeTagFn {
+	for _, v := range o {
+		if v.rtid == rtid {
+			return v
+		}
+	}
+	return nil
+}
+
+func (o extHandle) getExtForTag(tag byte) *extTypeTagFn {
+	for _, v := range o {
+		if v.tag == tag {
+			return v
+		}
+	}
+	return nil
+}
+
+func (o extHandle) getDecodeExtForTag(tag byte) (
+	rv reflect.Value, fn func(reflect.Value, []byte) error) {
+	if x := o.getExtForTag(tag); x != nil {
+		// ext is only registered for base
+		rv = reflect.New(x.rt).Elem()
+		fn = x.decFn
+	}
+	return
+}
+
+func (o extHandle) getDecodeExt(rtid uintptr) (tag byte, fn func(reflect.Value, []byte) error) {
+	if x := o.getExt(rtid); x != nil {
+		tag = x.tag
+		fn = x.decFn
+	}
+	return
+}
+
+func (o extHandle) getEncodeExt(rtid uintptr) (tag byte, fn func(reflect.Value) ([]byte, error)) {
+	if x := o.getExt(rtid); x != nil {
+		tag = x.tag
+		fn = x.encFn
+	}
+	return
+}
+
+type structFieldInfo struct {
+	encName string // encode name
+
+	// only one of 'i' or 'is' can be set. If 'i' is -1, then 'is' has been set.
+
+	is        []int // (recursive/embedded) field index in struct
+	i         int16 // field index in struct
+	omitEmpty bool
+	toArray   bool // if field is _struct, is the toArray set?
+
+	// tag       string   // tag
+	// name      string   // field name
+	// encNameBs []byte   // encoded name as byte stream
+	// ikind     int      // kind of the field as an int i.e. int(reflect.Kind)
+}
+
+func parseStructFieldInfo(fname string, stag string) *structFieldInfo {
+	if fname == "" {
+		panic("parseStructFieldInfo: No Field Name")
+	}
+	si := structFieldInfo{
+		// name: fname,
+		encName: fname,
+		// tag: stag,
+	}
+
+	if stag != "" {
+		for i, s := range strings.Split(stag, ",") {
+			if i == 0 {
+				if s != "" {
+					si.encName = s
+				}
+			} else {
+				switch s {
+				case "omitempty":
+					si.omitEmpty = true
+				case "toarray":
+					si.toArray = true
+				}
+			}
+		}
+	}
+	// si.encNameBs = []byte(si.encName)
+	return &si
+}
+
+type sfiSortedByEncName []*structFieldInfo
+
+func (p sfiSortedByEncName) Len() int {
+	return len(p)
+}
+
+func (p sfiSortedByEncName) Less(i, j int) bool {
+	return p[i].encName < p[j].encName
+}
+
+func (p sfiSortedByEncName) Swap(i, j int) {
+	p[i], p[j] = p[j], p[i]
+}
+
+// typeInfo keeps information about each type referenced in the encode/decode sequence.
+//
+// During an encode/decode sequence, we work as below:
+//   - If base is a built in type, en/decode base value
+//   - If base is registered as an extension, en/decode base value
+//   - If type is binary(M/Unm)arshaler, call Binary(M/Unm)arshal method
+//   - Else decode appropriately based on the reflect.Kind
+type typeInfo struct {
+	sfi  []*structFieldInfo // sorted. Used when enc/dec struct to map.
+	sfip []*structFieldInfo // unsorted. Used when enc/dec struct to array.
+
+	rt   reflect.Type
+	rtid uintptr
+
+	// baseId gives pointer to the base reflect.Type, after deferencing
+	// the pointers. E.g. base type of ***time.Time is time.Time.
+	base      reflect.Type
+	baseId    uintptr
+	baseIndir int8 // number of indirections to get to base
+
+	mbs bool // base type (T or *T) is a MapBySlice
+
+	m        bool // base type (T or *T) is a binaryMarshaler
+	unm      bool // base type (T or *T) is a binaryUnmarshaler
+	mIndir   int8 // number of indirections to get to binaryMarshaler type
+	unmIndir int8 // number of indirections to get to binaryUnmarshaler type
+	toArray  bool // whether this (struct) type should be encoded as an array
+}
+
+func (ti *typeInfo) indexForEncName(name string) int {
+	//tisfi := ti.sfi
+	const binarySearchThreshold = 16
+	if sfilen := len(ti.sfi); sfilen < binarySearchThreshold {
+		// linear search. faster than binary search in my testing up to 16-field structs.
+		for i, si := range ti.sfi {
+			if si.encName == name {
+				return i
+			}
+		}
+	} else {
+		// binary search. adapted from sort/search.go.
+		h, i, j := 0, 0, sfilen
+		for i < j {
+			h = i + (j-i)/2
+			if ti.sfi[h].encName < name {
+				i = h + 1
+			} else {
+				j = h
+			}
+		}
+		if i < sfilen && ti.sfi[i].encName == name {
+			return i
+		}
+	}
+	return -1
+}
+
+func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
+	var ok bool
+	cachedTypeInfoMutex.RLock()
+	pti, ok = cachedTypeInfo[rtid]
+	cachedTypeInfoMutex.RUnlock()
+	if ok {
+		return
+	}
+
+	cachedTypeInfoMutex.Lock()
+	defer cachedTypeInfoMutex.Unlock()
+	if pti, ok = cachedTypeInfo[rtid]; ok {
+		return
+	}
+
+	ti := typeInfo{rt: rt, rtid: rtid}
+	pti = &ti
+
+	var indir int8
+	if ok, indir = implementsIntf(rt, binaryMarshalerTyp); ok {
+		ti.m, ti.mIndir = true, indir
+	}
+	if ok, indir = implementsIntf(rt, binaryUnmarshalerTyp); ok {
+		ti.unm, ti.unmIndir = true, indir
+	}
+	if ok, _ = implementsIntf(rt, mapBySliceTyp); ok {
+		ti.mbs = true
+	}
+
+	pt := rt
+	var ptIndir int8
+	// for ; pt.Kind() == reflect.Ptr; pt, ptIndir = pt.Elem(), ptIndir+1 { }
+	for pt.Kind() == reflect.Ptr {
+		pt = pt.Elem()
+		ptIndir++
+	}
+	if ptIndir == 0 {
+		ti.base = rt
+		ti.baseId = rtid
+	} else {
+		ti.base = pt
+		ti.baseId = reflect.ValueOf(pt).Pointer()
+		ti.baseIndir = ptIndir
+	}
+
+	if rt.Kind() == reflect.Struct {
+		var siInfo *structFieldInfo
+		if f, ok := rt.FieldByName(structInfoFieldName); ok {
+			siInfo = parseStructFieldInfo(structInfoFieldName, f.Tag.Get(structTagName))
+			ti.toArray = siInfo.toArray
+		}
+		sfip := make([]*structFieldInfo, 0, rt.NumField())
+		rgetTypeInfo(rt, nil, make(map[string]bool), &sfip, siInfo)
+
+		// // try to put all si close together
+		// const tryToPutAllStructFieldInfoTogether = true
+		// if tryToPutAllStructFieldInfoTogether {
+		// 	sfip2 := make([]structFieldInfo, len(sfip))
+		// 	for i, si := range sfip {
+		// 		sfip2[i] = *si
+		// 	}
+		// 	for i := range sfip {
+		// 		sfip[i] = &sfip2[i]
+		// 	}
+		// }
+
+		ti.sfip = make([]*structFieldInfo, len(sfip))
+		ti.sfi = make([]*structFieldInfo, len(sfip))
+		copy(ti.sfip, sfip)
+		sort.Sort(sfiSortedByEncName(sfip))
+		copy(ti.sfi, sfip)
+	}
+	// sfi = sfip
+	cachedTypeInfo[rtid] = pti
+	return
+}
+
+func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool,
+	sfi *[]*structFieldInfo, siInfo *structFieldInfo,
+) {
+	// for rt.Kind() == reflect.Ptr {
+	// 	// indexstack = append(indexstack, 0)
+	// 	rt = rt.Elem()
+	// }
+	for j := 0; j < rt.NumField(); j++ {
+		f := rt.Field(j)
+		stag := f.Tag.Get(structTagName)
+		if stag == "-" {
+			continue
+		}
+		if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) {
+			continue
+		}
+		// if anonymous and there is no struct tag and its a struct (or pointer to struct), inline it.
+		if f.Anonymous && stag == "" {
+			ft := f.Type
+			for ft.Kind() == reflect.Ptr {
+				ft = ft.Elem()
+			}
+			if ft.Kind() == reflect.Struct {
+				indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
+				rgetTypeInfo(ft, indexstack2, fnameToHastag, sfi, siInfo)
+				continue
+			}
+		}
+		// do not let fields with same name in embedded structs override field at higher level.
+		// this must be done after anonymous check, to allow anonymous field
+		// still include their child fields
+		if _, ok := fnameToHastag[f.Name]; ok {
+			continue
+		}
+		si := parseStructFieldInfo(f.Name, stag)
+		// si.ikind = int(f.Type.Kind())
+		if len(indexstack) == 0 {
+			si.i = int16(j)
+		} else {
+			si.i = -1
+			si.is = append(append(make([]int, 0, len(indexstack)+4), indexstack...), j)
+		}
+
+		if siInfo != nil {
+			if siInfo.omitEmpty {
+				si.omitEmpty = true
+			}
+		}
+		*sfi = append(*sfi, si)
+		fnameToHastag[f.Name] = stag != ""
+	}
+}
+
+func panicToErr(err *error) {
+	if recoverPanicToErr {
+		if x := recover(); x != nil {
+			//debug.PrintStack()
+			panicValToErr(x, err)
+		}
+	}
+}
+
+func doPanic(tag string, format string, params ...interface{}) {
+	params2 := make([]interface{}, len(params)+1)
+	params2[0] = tag
+	copy(params2[1:], params)
+	panic(fmt.Errorf("%s: "+format, params2...))
+}
+
+func checkOverflowFloat32(f float64, doCheck bool) {
+	if !doCheck {
+		return
+	}
+	// check overflow (logic adapted from std pkg reflect/value.go OverflowFloat()
+	f2 := f
+	if f2 < 0 {
+		f2 = -f
+	}
+	if math.MaxFloat32 < f2 && f2 <= math.MaxFloat64 {
+		decErr("Overflow float32 value: %v", f2)
+	}
+}
+
+func checkOverflow(ui uint64, i int64, bitsize uint8) {
+	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
+	if bitsize == 0 {
+		return
+	}
+	if i != 0 {
+		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
+			decErr("Overflow int value: %v", i)
+		}
+	}
+	if ui != 0 {
+		if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
+			decErr("Overflow uint value: %v", ui)
+		}
+	}
+}

+ 127 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/helper_internal.go

@@ -0,0 +1,127 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// All non-std package dependencies live in this file,
+// so porting to different environment is easy (just update functions).
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"reflect"
+)
+
+var (
+	raisePanicAfterRecover = false
+	debugging              = true
+)
+
+func panicValToErr(panicVal interface{}, err *error) {
+	switch xerr := panicVal.(type) {
+	case error:
+		*err = xerr
+	case string:
+		*err = errors.New(xerr)
+	default:
+		*err = fmt.Errorf("%v", panicVal)
+	}
+	if raisePanicAfterRecover {
+		panic(panicVal)
+	}
+	return
+}
+
+func isEmptyValueDeref(v reflect.Value, deref bool) bool {
+	switch v.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		return v.Len() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		if deref {
+			if v.IsNil() {
+				return true
+			}
+			return isEmptyValueDeref(v.Elem(), deref)
+		} else {
+			return v.IsNil()
+		}
+	case reflect.Struct:
+		// return true if all fields are empty. else return false.
+
+		// we cannot use equality check, because some fields may be maps/slices/etc
+		// and consequently the structs are not comparable.
+		// return v.Interface() == reflect.Zero(v.Type()).Interface()
+		for i, n := 0, v.NumField(); i < n; i++ {
+			if !isEmptyValueDeref(v.Field(i), deref) {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}
+
+func isEmptyValue(v reflect.Value) bool {
+	return isEmptyValueDeref(v, true)
+}
+
+func debugf(format string, args ...interface{}) {
+	if debugging {
+		if len(format) == 0 || format[len(format)-1] != '\n' {
+			format = format + "\n"
+		}
+		fmt.Printf(format, args...)
+	}
+}
+
+func pruneSignExt(v []byte, pos bool) (n int) {
+	if len(v) < 2 {
+	} else if pos && v[0] == 0 {
+		for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ {
+		}
+	} else if !pos && v[0] == 0xff {
+		for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ {
+		}
+	}
+	return
+}
+
+func implementsIntf(typ, iTyp reflect.Type) (success bool, indir int8) {
+	if typ == nil {
+		return
+	}
+	rt := typ
+	// The type might be a pointer and we need to keep
+	// dereferencing to the base type until we find an implementation.
+	for {
+		if rt.Implements(iTyp) {
+			return true, indir
+		}
+		if p := rt; p.Kind() == reflect.Ptr {
+			indir++
+			if indir >= math.MaxInt8 { // insane number of indirections
+				return false, 0
+			}
+			rt = p.Elem()
+			continue
+		}
+		break
+	}
+	// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
+	if typ.Kind() != reflect.Ptr {
+		// Not a pointer, but does the pointer work?
+		if reflect.PtrTo(typ).Implements(iTyp) {
+			return true, -1
+		}
+	}
+	return false, 0
+}

+ 816 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack.go

@@ -0,0 +1,816 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+/*
+MSGPACK
+
+Msgpack-c implementation powers the c, c++, python, ruby, etc libraries.
+We need to maintain compatibility with it and how it encodes integer values
+without caring about the type.
+
+For compatibility with behaviour of msgpack-c reference implementation:
+  - Go intX (>0) and uintX
+       IS ENCODED AS
+    msgpack +ve fixnum, unsigned
+  - Go intX (<0)
+       IS ENCODED AS
+    msgpack -ve fixnum, signed
+
+*/
+package codec
+
+import (
+	"fmt"
+	"io"
+	"math"
+	"net/rpc"
+)
+
+const (
+	mpPosFixNumMin byte = 0x00
+	mpPosFixNumMax      = 0x7f
+	mpFixMapMin         = 0x80
+	mpFixMapMax         = 0x8f
+	mpFixArrayMin       = 0x90
+	mpFixArrayMax       = 0x9f
+	mpFixStrMin         = 0xa0
+	mpFixStrMax         = 0xbf
+	mpNil               = 0xc0
+	_                   = 0xc1
+	mpFalse             = 0xc2
+	mpTrue              = 0xc3
+	mpFloat             = 0xca
+	mpDouble            = 0xcb
+	mpUint8             = 0xcc
+	mpUint16            = 0xcd
+	mpUint32            = 0xce
+	mpUint64            = 0xcf
+	mpInt8              = 0xd0
+	mpInt16             = 0xd1
+	mpInt32             = 0xd2
+	mpInt64             = 0xd3
+
+	// extensions below
+	mpBin8     = 0xc4
+	mpBin16    = 0xc5
+	mpBin32    = 0xc6
+	mpExt8     = 0xc7
+	mpExt16    = 0xc8
+	mpExt32    = 0xc9
+	mpFixExt1  = 0xd4
+	mpFixExt2  = 0xd5
+	mpFixExt4  = 0xd6
+	mpFixExt8  = 0xd7
+	mpFixExt16 = 0xd8
+
+	mpStr8  = 0xd9 // new
+	mpStr16 = 0xda
+	mpStr32 = 0xdb
+
+	mpArray16 = 0xdc
+	mpArray32 = 0xdd
+
+	mpMap16 = 0xde
+	mpMap32 = 0xdf
+
+	mpNegFixNumMin = 0xe0
+	mpNegFixNumMax = 0xff
+)
+
+// MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec
+// that the backend RPC service takes multiple arguments, which have been arranged
+// in sequence in the slice.
+//
+// The Codec then passes it AS-IS to the rpc service (without wrapping it in an
+// array of 1 element).
+type MsgpackSpecRpcMultiArgs []interface{}
+
+// A MsgpackContainer type specifies the different types of msgpackContainers.
+type msgpackContainerType struct {
+	fixCutoff                   int
+	bFixMin, b8, b16, b32       byte
+	hasFixMin, has8, has8Always bool
+}
+
+var (
+	msgpackContainerStr  = msgpackContainerType{32, mpFixStrMin, mpStr8, mpStr16, mpStr32, true, true, false}
+	msgpackContainerBin  = msgpackContainerType{0, 0, mpBin8, mpBin16, mpBin32, false, true, true}
+	msgpackContainerList = msgpackContainerType{16, mpFixArrayMin, 0, mpArray16, mpArray32, true, false, false}
+	msgpackContainerMap  = msgpackContainerType{16, mpFixMapMin, 0, mpMap16, mpMap32, true, false, false}
+)
+
+//---------------------------------------------
+
+type msgpackEncDriver struct {
+	w encWriter
+	h *MsgpackHandle
+}
+
+func (e *msgpackEncDriver) isBuiltinType(rt uintptr) bool {
+	//no builtin types. All encodings are based on kinds. Types supported as extensions.
+	return false
+}
+
+func (e *msgpackEncDriver) encodeBuiltin(rt uintptr, v interface{}) {}
+
+func (e *msgpackEncDriver) encodeNil() {
+	e.w.writen1(mpNil)
+}
+
+func (e *msgpackEncDriver) encodeInt(i int64) {
+
+	switch {
+	case i >= 0:
+		e.encodeUint(uint64(i))
+	case i >= -32:
+		e.w.writen1(byte(i))
+	case i >= math.MinInt8:
+		e.w.writen2(mpInt8, byte(i))
+	case i >= math.MinInt16:
+		e.w.writen1(mpInt16)
+		e.w.writeUint16(uint16(i))
+	case i >= math.MinInt32:
+		e.w.writen1(mpInt32)
+		e.w.writeUint32(uint32(i))
+	default:
+		e.w.writen1(mpInt64)
+		e.w.writeUint64(uint64(i))
+	}
+}
+
+func (e *msgpackEncDriver) encodeUint(i uint64) {
+	switch {
+	case i <= math.MaxInt8:
+		e.w.writen1(byte(i))
+	case i <= math.MaxUint8:
+		e.w.writen2(mpUint8, byte(i))
+	case i <= math.MaxUint16:
+		e.w.writen1(mpUint16)
+		e.w.writeUint16(uint16(i))
+	case i <= math.MaxUint32:
+		e.w.writen1(mpUint32)
+		e.w.writeUint32(uint32(i))
+	default:
+		e.w.writen1(mpUint64)
+		e.w.writeUint64(uint64(i))
+	}
+}
+
+func (e *msgpackEncDriver) encodeBool(b bool) {
+	if b {
+		e.w.writen1(mpTrue)
+	} else {
+		e.w.writen1(mpFalse)
+	}
+}
+
+func (e *msgpackEncDriver) encodeFloat32(f float32) {
+	e.w.writen1(mpFloat)
+	e.w.writeUint32(math.Float32bits(f))
+}
+
+func (e *msgpackEncDriver) encodeFloat64(f float64) {
+	e.w.writen1(mpDouble)
+	e.w.writeUint64(math.Float64bits(f))
+}
+
+func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) {
+	switch {
+	case l == 1:
+		e.w.writen2(mpFixExt1, xtag)
+	case l == 2:
+		e.w.writen2(mpFixExt2, xtag)
+	case l == 4:
+		e.w.writen2(mpFixExt4, xtag)
+	case l == 8:
+		e.w.writen2(mpFixExt8, xtag)
+	case l == 16:
+		e.w.writen2(mpFixExt16, xtag)
+	case l < 256:
+		e.w.writen2(mpExt8, byte(l))
+		e.w.writen1(xtag)
+	case l < 65536:
+		e.w.writen1(mpExt16)
+		e.w.writeUint16(uint16(l))
+		e.w.writen1(xtag)
+	default:
+		e.w.writen1(mpExt32)
+		e.w.writeUint32(uint32(l))
+		e.w.writen1(xtag)
+	}
+}
+
+func (e *msgpackEncDriver) encodeArrayPreamble(length int) {
+	e.writeContainerLen(msgpackContainerList, length)
+}
+
+func (e *msgpackEncDriver) encodeMapPreamble(length int) {
+	e.writeContainerLen(msgpackContainerMap, length)
+}
+
+func (e *msgpackEncDriver) encodeString(c charEncoding, s string) {
+	if c == c_RAW && e.h.WriteExt {
+		e.writeContainerLen(msgpackContainerBin, len(s))
+	} else {
+		e.writeContainerLen(msgpackContainerStr, len(s))
+	}
+	if len(s) > 0 {
+		e.w.writestr(s)
+	}
+}
+
+func (e *msgpackEncDriver) encodeSymbol(v string) {
+	e.encodeString(c_UTF8, v)
+}
+
+func (e *msgpackEncDriver) encodeStringBytes(c charEncoding, bs []byte) {
+	if c == c_RAW && e.h.WriteExt {
+		e.writeContainerLen(msgpackContainerBin, len(bs))
+	} else {
+		e.writeContainerLen(msgpackContainerStr, len(bs))
+	}
+	if len(bs) > 0 {
+		e.w.writeb(bs)
+	}
+}
+
+func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) {
+	switch {
+	case ct.hasFixMin && l < ct.fixCutoff:
+		e.w.writen1(ct.bFixMin | byte(l))
+	case ct.has8 && l < 256 && (ct.has8Always || e.h.WriteExt):
+		e.w.writen2(ct.b8, uint8(l))
+	case l < 65536:
+		e.w.writen1(ct.b16)
+		e.w.writeUint16(uint16(l))
+	default:
+		e.w.writen1(ct.b32)
+		e.w.writeUint32(uint32(l))
+	}
+}
+
+//---------------------------------------------
+
+type msgpackDecDriver struct {
+	r      decReader
+	h      *MsgpackHandle
+	bd     byte
+	bdRead bool
+	bdType valueType
+}
+
+func (d *msgpackDecDriver) isBuiltinType(rt uintptr) bool {
+	//no builtin types. All encodings are based on kinds. Types supported as extensions.
+	return false
+}
+
+func (d *msgpackDecDriver) decodeBuiltin(rt uintptr, v interface{}) {}
+
+// Note: This returns either a primitive (int, bool, etc) for non-containers,
+// or a containerType, or a specific type denoting nil or extension.
+// It is called when a nil interface{} is passed, leaving it up to the DecDriver
+// to introspect the stream and decide how best to decode.
+// It deciphers the value by looking at the stream first.
+func (d *msgpackDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
+	d.initReadNext()
+	bd := d.bd
+
+	switch bd {
+	case mpNil:
+		vt = valueTypeNil
+		d.bdRead = false
+	case mpFalse:
+		vt = valueTypeBool
+		v = false
+	case mpTrue:
+		vt = valueTypeBool
+		v = true
+
+	case mpFloat:
+		vt = valueTypeFloat
+		v = float64(math.Float32frombits(d.r.readUint32()))
+	case mpDouble:
+		vt = valueTypeFloat
+		v = math.Float64frombits(d.r.readUint64())
+
+	case mpUint8:
+		vt = valueTypeUint
+		v = uint64(d.r.readn1())
+	case mpUint16:
+		vt = valueTypeUint
+		v = uint64(d.r.readUint16())
+	case mpUint32:
+		vt = valueTypeUint
+		v = uint64(d.r.readUint32())
+	case mpUint64:
+		vt = valueTypeUint
+		v = uint64(d.r.readUint64())
+
+	case mpInt8:
+		vt = valueTypeInt
+		v = int64(int8(d.r.readn1()))
+	case mpInt16:
+		vt = valueTypeInt
+		v = int64(int16(d.r.readUint16()))
+	case mpInt32:
+		vt = valueTypeInt
+		v = int64(int32(d.r.readUint32()))
+	case mpInt64:
+		vt = valueTypeInt
+		v = int64(int64(d.r.readUint64()))
+
+	default:
+		switch {
+		case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
+			// positive fixnum (always signed)
+			vt = valueTypeInt
+			v = int64(int8(bd))
+		case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
+			// negative fixnum
+			vt = valueTypeInt
+			v = int64(int8(bd))
+		case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
+			if d.h.RawToString {
+				var rvm string
+				vt = valueTypeString
+				v = &rvm
+			} else {
+				var rvm = []byte{}
+				vt = valueTypeBytes
+				v = &rvm
+			}
+			decodeFurther = true
+		case bd == mpBin8, bd == mpBin16, bd == mpBin32:
+			var rvm = []byte{}
+			vt = valueTypeBytes
+			v = &rvm
+			decodeFurther = true
+		case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
+			vt = valueTypeArray
+			decodeFurther = true
+		case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
+			vt = valueTypeMap
+			decodeFurther = true
+		case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
+			clen := d.readExtLen()
+			var re RawExt
+			re.Tag = d.r.readn1()
+			re.Data = d.r.readn(clen)
+			v = &re
+			vt = valueTypeExt
+		default:
+			decErr("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+		}
+	}
+	if !decodeFurther {
+		d.bdRead = false
+	}
+	return
+}
+
+// int can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) decodeInt(bitsize uint8) (i int64) {
+	switch d.bd {
+	case mpUint8:
+		i = int64(uint64(d.r.readn1()))
+	case mpUint16:
+		i = int64(uint64(d.r.readUint16()))
+	case mpUint32:
+		i = int64(uint64(d.r.readUint32()))
+	case mpUint64:
+		i = int64(d.r.readUint64())
+	case mpInt8:
+		i = int64(int8(d.r.readn1()))
+	case mpInt16:
+		i = int64(int16(d.r.readUint16()))
+	case mpInt32:
+		i = int64(int32(d.r.readUint32()))
+	case mpInt64:
+		i = int64(d.r.readUint64())
+	default:
+		switch {
+		case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
+			i = int64(int8(d.bd))
+		case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
+			i = int64(int8(d.bd))
+		default:
+			decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+		}
+	}
+	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
+	if bitsize > 0 {
+		if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc {
+			decErr("Overflow int value: %v", i)
+		}
+	}
+	d.bdRead = false
+	return
+}
+
+// uint can be decoded from msgpack type: intXXX or uintXXX
+func (d *msgpackDecDriver) decodeUint(bitsize uint8) (ui uint64) {
+	switch d.bd {
+	case mpUint8:
+		ui = uint64(d.r.readn1())
+	case mpUint16:
+		ui = uint64(d.r.readUint16())
+	case mpUint32:
+		ui = uint64(d.r.readUint32())
+	case mpUint64:
+		ui = d.r.readUint64()
+	case mpInt8:
+		if i := int64(int8(d.r.readn1())); i >= 0 {
+			ui = uint64(i)
+		} else {
+			decErr("Assigning negative signed value: %v, to unsigned type", i)
+		}
+	case mpInt16:
+		if i := int64(int16(d.r.readUint16())); i >= 0 {
+			ui = uint64(i)
+		} else {
+			decErr("Assigning negative signed value: %v, to unsigned type", i)
+		}
+	case mpInt32:
+		if i := int64(int32(d.r.readUint32())); i >= 0 {
+			ui = uint64(i)
+		} else {
+			decErr("Assigning negative signed value: %v, to unsigned type", i)
+		}
+	case mpInt64:
+		if i := int64(d.r.readUint64()); i >= 0 {
+			ui = uint64(i)
+		} else {
+			decErr("Assigning negative signed value: %v, to unsigned type", i)
+		}
+	default:
+		switch {
+		case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax:
+			ui = uint64(d.bd)
+		case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax:
+			decErr("Assigning negative signed value: %v, to unsigned type", int(d.bd))
+		default:
+			decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd)
+		}
+	}
+	// check overflow (logic adapted from std pkg reflect/value.go OverflowUint()
+	if bitsize > 0 {
+		if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc {
+			decErr("Overflow uint value: %v", ui)
+		}
+	}
+	d.bdRead = false
+	return
+}
+
+// float can either be decoded from msgpack type: float, double or intX
+func (d *msgpackDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
+	switch d.bd {
+	case mpFloat:
+		f = float64(math.Float32frombits(d.r.readUint32()))
+	case mpDouble:
+		f = math.Float64frombits(d.r.readUint64())
+	default:
+		f = float64(d.decodeInt(0))
+	}
+	checkOverflowFloat32(f, chkOverflow32)
+	d.bdRead = false
+	return
+}
+
+// bool can be decoded from bool, fixnum 0 or 1.
+func (d *msgpackDecDriver) decodeBool() (b bool) {
+	switch d.bd {
+	case mpFalse, 0:
+		// b = false
+	case mpTrue, 1:
+		b = true
+	default:
+		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *msgpackDecDriver) decodeString() (s string) {
+	clen := d.readContainerLen(msgpackContainerStr)
+	if clen > 0 {
+		s = string(d.r.readn(clen))
+	}
+	d.bdRead = false
+	return
+}
+
+// Callers must check if changed=true (to decide whether to replace the one they have)
+func (d *msgpackDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
+	// bytes can be decoded from msgpackContainerStr or msgpackContainerBin
+	var clen int
+	switch d.bd {
+	case mpBin8, mpBin16, mpBin32:
+		clen = d.readContainerLen(msgpackContainerBin)
+	default:
+		clen = d.readContainerLen(msgpackContainerStr)
+	}
+	// if clen < 0 {
+	// 	changed = true
+	// 	panic("length cannot be zero. this cannot be nil.")
+	// }
+	if clen > 0 {
+		// if no contents in stream, don't update the passed byteslice
+		if len(bs) != clen {
+			// Return changed=true if length of passed slice diff from length of bytes in stream
+			if len(bs) > clen {
+				bs = bs[:clen]
+			} else {
+				bs = make([]byte, clen)
+			}
+			bsOut = bs
+			changed = true
+		}
+		d.r.readb(bs)
+	}
+	d.bdRead = false
+	return
+}
+
+// Every top-level decode funcs (i.e. decodeValue, decode) must call this first.
+func (d *msgpackDecDriver) initReadNext() {
+	if d.bdRead {
+		return
+	}
+	d.bd = d.r.readn1()
+	d.bdRead = true
+	d.bdType = valueTypeUnset
+}
+
+func (d *msgpackDecDriver) currentEncodedType() valueType {
+	if d.bdType == valueTypeUnset {
+		bd := d.bd
+		switch bd {
+		case mpNil:
+			d.bdType = valueTypeNil
+		case mpFalse, mpTrue:
+			d.bdType = valueTypeBool
+		case mpFloat, mpDouble:
+			d.bdType = valueTypeFloat
+		case mpUint8, mpUint16, mpUint32, mpUint64:
+			d.bdType = valueTypeUint
+		case mpInt8, mpInt16, mpInt32, mpInt64:
+			d.bdType = valueTypeInt
+		default:
+			switch {
+			case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax:
+				d.bdType = valueTypeInt
+			case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax:
+				d.bdType = valueTypeInt
+			case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax:
+				if d.h.RawToString {
+					d.bdType = valueTypeString
+				} else {
+					d.bdType = valueTypeBytes
+				}
+			case bd == mpBin8, bd == mpBin16, bd == mpBin32:
+				d.bdType = valueTypeBytes
+			case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax:
+				d.bdType = valueTypeArray
+			case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax:
+				d.bdType = valueTypeMap
+			case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32:
+				d.bdType = valueTypeExt
+			default:
+				decErr("currentEncodedType: Undeciphered descriptor: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+			}
+		}
+	}
+	return d.bdType
+}
+
+func (d *msgpackDecDriver) tryDecodeAsNil() bool {
+	if d.bd == mpNil {
+		d.bdRead = false
+		return true
+	}
+	return false
+}
+
+func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) {
+	bd := d.bd
+	switch {
+	case bd == mpNil:
+		clen = -1 // to represent nil
+	case bd == ct.b8:
+		clen = int(d.r.readn1())
+	case bd == ct.b16:
+		clen = int(d.r.readUint16())
+	case bd == ct.b32:
+		clen = int(d.r.readUint32())
+	case (ct.bFixMin & bd) == ct.bFixMin:
+		clen = int(ct.bFixMin ^ bd)
+	default:
+		decErr("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, bd, bd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *msgpackDecDriver) readMapLen() int {
+	return d.readContainerLen(msgpackContainerMap)
+}
+
+func (d *msgpackDecDriver) readArrayLen() int {
+	return d.readContainerLen(msgpackContainerList)
+}
+
+func (d *msgpackDecDriver) readExtLen() (clen int) {
+	switch d.bd {
+	case mpNil:
+		clen = -1 // to represent nil
+	case mpFixExt1:
+		clen = 1
+	case mpFixExt2:
+		clen = 2
+	case mpFixExt4:
+		clen = 4
+	case mpFixExt8:
+		clen = 8
+	case mpFixExt16:
+		clen = 16
+	case mpExt8:
+		clen = int(d.r.readn1())
+	case mpExt16:
+		clen = int(d.r.readUint16())
+	case mpExt32:
+		clen = int(d.r.readUint32())
+	default:
+		decErr("decoding ext bytes: found unexpected byte: %x", d.bd)
+	}
+	return
+}
+
+func (d *msgpackDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) {
+	xbd := d.bd
+	switch {
+	case xbd == mpBin8, xbd == mpBin16, xbd == mpBin32:
+		xbs, _ = d.decodeBytes(nil)
+	case xbd == mpStr8, xbd == mpStr16, xbd == mpStr32,
+		xbd >= mpFixStrMin && xbd <= mpFixStrMax:
+		xbs = []byte(d.decodeString())
+	default:
+		clen := d.readExtLen()
+		xtag = d.r.readn1()
+		if verifyTag && xtag != tag {
+			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+		}
+		xbs = d.r.readn(clen)
+	}
+	d.bdRead = false
+	return
+}
+
+//--------------------------------------------------
+
+//MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format.
+type MsgpackHandle struct {
+	BasicHandle
+
+	// RawToString controls how raw bytes are decoded into a nil interface{}.
+	RawToString bool
+	// WriteExt flag supports encoding configured extensions with extension tags.
+	// It also controls whether other elements of the new spec are encoded (ie Str8).
+	//
+	// With WriteExt=false, configured extensions are serialized as raw bytes
+	// and Str8 is not encoded.
+	//
+	// A stream can still be decoded into a typed value, provided an appropriate value
+	// is provided, but the type cannot be inferred from the stream. If no appropriate
+	// type is provided (e.g. decoding into a nil interface{}), you get back
+	// a []byte or string based on the setting of RawToString.
+	WriteExt bool
+}
+
+func (h *MsgpackHandle) newEncDriver(w encWriter) encDriver {
+	return &msgpackEncDriver{w: w, h: h}
+}
+
+func (h *MsgpackHandle) newDecDriver(r decReader) decDriver {
+	return &msgpackDecDriver{r: r, h: h}
+}
+
+func (h *MsgpackHandle) writeExt() bool {
+	return h.WriteExt
+}
+
+func (h *MsgpackHandle) getBasicHandle() *BasicHandle {
+	return &h.BasicHandle
+}
+
+//--------------------------------------------------
+
+type msgpackSpecRpcCodec struct {
+	rpcCodec
+}
+
+// /////////////// Spec RPC Codec ///////////////////
+func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
+	// WriteRequest can write to both a Go service, and other services that do
+	// not abide by the 1 argument rule of a Go service.
+	// We discriminate based on if the body is a MsgpackSpecRpcMultiArgs
+	var bodyArr []interface{}
+	if m, ok := body.(MsgpackSpecRpcMultiArgs); ok {
+		bodyArr = ([]interface{})(m)
+	} else {
+		bodyArr = []interface{}{body}
+	}
+	r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr}
+	return c.write(r2, nil, false, true)
+}
+
+func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
+	var moe interface{}
+	if r.Error != "" {
+		moe = r.Error
+	}
+	if moe != nil && body != nil {
+		body = nil
+	}
+	r2 := []interface{}{1, uint32(r.Seq), moe, body}
+	return c.write(r2, nil, false, true)
+}
+
+func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error {
+	return c.parseCustomHeader(1, &r.Seq, &r.Error)
+}
+
+func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error {
+	return c.parseCustomHeader(0, &r.Seq, &r.ServiceMethod)
+}
+
+func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error {
+	if body == nil { // read and discard
+		return c.read(nil)
+	}
+	bodyArr := []interface{}{body}
+	return c.read(&bodyArr)
+}
+
+func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) {
+
+	if c.cls {
+		return io.EOF
+	}
+
+	// We read the response header by hand
+	// so that the body can be decoded on its own from the stream at a later time.
+
+	const fia byte = 0x94 //four item array descriptor value
+	// Not sure why the panic of EOF is swallowed above.
+	// if bs1 := c.dec.r.readn1(); bs1 != fia {
+	// 	err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1)
+	// 	return
+	// }
+	var b byte
+	b, err = c.br.ReadByte()
+	if err != nil {
+		return
+	}
+	if b != fia {
+		err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, b)
+		return
+	}
+
+	if err = c.read(&b); err != nil {
+		return
+	}
+	if b != expectTypeByte {
+		err = fmt.Errorf("Unexpected byte descriptor in header. Expecting %v. Received %v", expectTypeByte, b)
+		return
+	}
+	if err = c.read(msgid); err != nil {
+		return
+	}
+	if err = c.read(methodOrError); err != nil {
+		return
+	}
+	return
+}
+
+//--------------------------------------------------
+
+// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol
+// as defined in the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
+type msgpackSpecRpc struct{}
+
+// MsgpackSpecRpc implements Rpc using the communication protocol defined in
+// the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md .
+// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered.
+var MsgpackSpecRpc msgpackSpecRpc
+
+func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+	return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
+}
+
+func (x msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+	return &msgpackSpecRpcCodec{newRPCCodec(conn, h)}
+}
+
+var _ decDriver = (*msgpackDecDriver)(nil)
+var _ encDriver = (*msgpackEncDriver)(nil)

+ 110 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/msgpack_test.py

@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+
+# This will create golden files in a directory passed to it.
+# A Test calls this internally to create the golden files
+# So it can process them (so we don't have to checkin the files).
+
+import msgpack, msgpackrpc, sys, os, threading
+
+def get_test_data_list():
+    # get list with all primitive types, and a combo type
+    l0 = [ 
+        -8,
+         -1616,
+         -32323232,
+         -6464646464646464,
+         192,
+         1616,
+         32323232,
+         6464646464646464,
+         192,
+         -3232.0,
+         -6464646464.0,
+         3232.0,
+         6464646464.0,
+         False,
+         True,
+         None,
+         "someday",
+         "",
+         "bytestring",
+         1328176922000002000,
+         -2206187877999998000,
+         0,
+         -6795364578871345152
+         ]
+    l1 = [
+        { "true": True,
+          "false": False },
+        { "true": "True",
+          "false": False,
+          "uint16(1616)": 1616 },
+        { "list": [1616, 32323232, True, -3232.0, {"TRUE":True, "FALSE":False}, [True, False] ],
+          "int32":32323232, "bool": True, 
+          "LONG STRING": "123456789012345678901234567890123456789012345678901234567890",
+          "SHORT STRING": "1234567890" },	
+        { True: "true", 8: False, "false": 0 }
+        ]
+    
+    l = []
+    l.extend(l0)
+    l.append(l0)
+    l.extend(l1)
+    return l
+
+def build_test_data(destdir):
+    l = get_test_data_list()
+    for i in range(len(l)):
+        packer = msgpack.Packer()
+        serialized = packer.pack(l[i])
+        f = open(os.path.join(destdir, str(i) + '.golden'), 'wb')
+        f.write(serialized)
+        f.close()
+
+def doRpcServer(port, stopTimeSec):
+    class EchoHandler(object):
+        def Echo123(self, msg1, msg2, msg3):
+            return ("1:%s 2:%s 3:%s" % (msg1, msg2, msg3))
+        def EchoStruct(self, msg):
+            return ("%s" % msg)
+    
+    addr = msgpackrpc.Address('localhost', port)
+    server = msgpackrpc.Server(EchoHandler())
+    server.listen(addr)
+    # run thread to stop it after stopTimeSec seconds if > 0
+    if stopTimeSec > 0:
+        def myStopRpcServer():
+            server.stop()
+        t = threading.Timer(stopTimeSec, myStopRpcServer)
+        t.start()
+    server.start()
+
+def doRpcClientToPythonSvc(port):
+    address = msgpackrpc.Address('localhost', port)
+    client = msgpackrpc.Client(address, unpack_encoding='utf-8')
+    print client.call("Echo123", "A1", "B2", "C3")
+    print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})
+   
+def doRpcClientToGoSvc(port):
+    # print ">>>> port: ", port, " <<<<<"
+    address = msgpackrpc.Address('localhost', port)
+    client = msgpackrpc.Client(address, unpack_encoding='utf-8')
+    print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"])
+    print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})
+
+def doMain(args):
+    if len(args) == 2 and args[0] == "testdata":
+        build_test_data(args[1])
+    elif len(args) == 3 and args[0] == "rpc-server":
+        doRpcServer(int(args[1]), int(args[2]))
+    elif len(args) == 2 and args[0] == "rpc-client-python-service":
+        doRpcClientToPythonSvc(int(args[1]))
+    elif len(args) == 2 and args[0] == "rpc-client-go-service":
+        doRpcClientToGoSvc(int(args[1]))
+    else:
+        print("Usage: msgpack_test.py " + 
+              "[testdata|rpc-server|rpc-client-python-service|rpc-client-go-service] ...")
+    
+if __name__ == "__main__":
+    doMain(sys.argv[1:])
+

+ 152 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/rpc.go

@@ -0,0 +1,152 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"bufio"
+	"io"
+	"net/rpc"
+	"sync"
+)
+
+// Rpc provides a rpc Server or Client Codec for rpc communication.
+type Rpc interface {
+	ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec
+	ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec
+}
+
+// RpcCodecBuffered allows access to the underlying bufio.Reader/Writer
+// used by the rpc connection. It accomodates use-cases where the connection
+// should be used by rpc and non-rpc functions, e.g. streaming a file after
+// sending an rpc response.
+type RpcCodecBuffered interface {
+	BufferedReader() *bufio.Reader
+	BufferedWriter() *bufio.Writer
+}
+
+// -------------------------------------
+
+// rpcCodec defines the struct members and common methods.
+type rpcCodec struct {
+	rwc io.ReadWriteCloser
+	dec *Decoder
+	enc *Encoder
+	bw  *bufio.Writer
+	br  *bufio.Reader
+	mu  sync.Mutex
+	cls bool
+}
+
+func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec {
+	bw := bufio.NewWriter(conn)
+	br := bufio.NewReader(conn)
+	return rpcCodec{
+		rwc: conn,
+		bw:  bw,
+		br:  br,
+		enc: NewEncoder(bw, h),
+		dec: NewDecoder(br, h),
+	}
+}
+
+func (c *rpcCodec) BufferedReader() *bufio.Reader {
+	return c.br
+}
+
+func (c *rpcCodec) BufferedWriter() *bufio.Writer {
+	return c.bw
+}
+
+func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error) {
+	if c.cls {
+		return io.EOF
+	}
+	if err = c.enc.Encode(obj1); err != nil {
+		return
+	}
+	if writeObj2 {
+		if err = c.enc.Encode(obj2); err != nil {
+			return
+		}
+	}
+	if doFlush && c.bw != nil {
+		return c.bw.Flush()
+	}
+	return
+}
+
+func (c *rpcCodec) read(obj interface{}) (err error) {
+	if c.cls {
+		return io.EOF
+	}
+	//If nil is passed in, we should still attempt to read content to nowhere.
+	if obj == nil {
+		var obj2 interface{}
+		return c.dec.Decode(&obj2)
+	}
+	return c.dec.Decode(obj)
+}
+
+func (c *rpcCodec) Close() error {
+	if c.cls {
+		return io.EOF
+	}
+	c.cls = true
+	return c.rwc.Close()
+}
+
+func (c *rpcCodec) ReadResponseBody(body interface{}) error {
+	return c.read(body)
+}
+
+// -------------------------------------
+
+type goRpcCodec struct {
+	rpcCodec
+}
+
+func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
+	// Must protect for concurrent access as per API
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.write(r, body, true, true)
+}
+
+func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.write(r, body, true, true)
+}
+
+func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error {
+	return c.read(r)
+}
+
+func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error {
+	return c.read(r)
+}
+
+func (c *goRpcCodec) ReadRequestBody(body interface{}) error {
+	return c.read(body)
+}
+
+// -------------------------------------
+
+// goRpc is the implementation of Rpc that uses the communication protocol
+// as defined in net/rpc package.
+type goRpc struct{}
+
+// GoRpc implements Rpc using the communication protocol defined in net/rpc package.
+// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered.
+var GoRpc goRpc
+
+func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec {
+	return &goRpcCodec{newRPCCodec(conn, h)}
+}
+
+func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec {
+	return &goRpcCodec{newRPCCodec(conn, h)}
+}
+
+var _ RpcCodecBuffered = (*rpcCodec)(nil) // ensure *rpcCodec implements RpcCodecBuffered

+ 461 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/simple.go

@@ -0,0 +1,461 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import "math"
+
+const (
+	_               uint8 = iota
+	simpleVdNil           = 1
+	simpleVdFalse         = 2
+	simpleVdTrue          = 3
+	simpleVdFloat32       = 4
+	simpleVdFloat64       = 5
+
+	// each lasts for 4 (ie n, n+1, n+2, n+3)
+	simpleVdPosInt = 8
+	simpleVdNegInt = 12
+
+	// containers: each lasts for 4 (ie n, n+1, n+2, ... n+7)
+	simpleVdString    = 216
+	simpleVdByteArray = 224
+	simpleVdArray     = 232
+	simpleVdMap       = 240
+	simpleVdExt       = 248
+)
+
+type simpleEncDriver struct {
+	h *SimpleHandle
+	w encWriter
+	//b [8]byte
+}
+
+func (e *simpleEncDriver) isBuiltinType(rt uintptr) bool {
+	return false
+}
+
+func (e *simpleEncDriver) encodeBuiltin(rt uintptr, v interface{}) {
+}
+
+func (e *simpleEncDriver) encodeNil() {
+	e.w.writen1(simpleVdNil)
+}
+
+func (e *simpleEncDriver) encodeBool(b bool) {
+	if b {
+		e.w.writen1(simpleVdTrue)
+	} else {
+		e.w.writen1(simpleVdFalse)
+	}
+}
+
+func (e *simpleEncDriver) encodeFloat32(f float32) {
+	e.w.writen1(simpleVdFloat32)
+	e.w.writeUint32(math.Float32bits(f))
+}
+
+func (e *simpleEncDriver) encodeFloat64(f float64) {
+	e.w.writen1(simpleVdFloat64)
+	e.w.writeUint64(math.Float64bits(f))
+}
+
+func (e *simpleEncDriver) encodeInt(v int64) {
+	if v < 0 {
+		e.encUint(uint64(-v), simpleVdNegInt)
+	} else {
+		e.encUint(uint64(v), simpleVdPosInt)
+	}
+}
+
+func (e *simpleEncDriver) encodeUint(v uint64) {
+	e.encUint(v, simpleVdPosInt)
+}
+
+func (e *simpleEncDriver) encUint(v uint64, bd uint8) {
+	switch {
+	case v <= math.MaxUint8:
+		e.w.writen2(bd, uint8(v))
+	case v <= math.MaxUint16:
+		e.w.writen1(bd + 1)
+		e.w.writeUint16(uint16(v))
+	case v <= math.MaxUint32:
+		e.w.writen1(bd + 2)
+		e.w.writeUint32(uint32(v))
+	case v <= math.MaxUint64:
+		e.w.writen1(bd + 3)
+		e.w.writeUint64(v)
+	}
+}
+
+func (e *simpleEncDriver) encLen(bd byte, length int) {
+	switch {
+	case length == 0:
+		e.w.writen1(bd)
+	case length <= math.MaxUint8:
+		e.w.writen1(bd + 1)
+		e.w.writen1(uint8(length))
+	case length <= math.MaxUint16:
+		e.w.writen1(bd + 2)
+		e.w.writeUint16(uint16(length))
+	case int64(length) <= math.MaxUint32:
+		e.w.writen1(bd + 3)
+		e.w.writeUint32(uint32(length))
+	default:
+		e.w.writen1(bd + 4)
+		e.w.writeUint64(uint64(length))
+	}
+}
+
+func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) {
+	e.encLen(simpleVdExt, length)
+	e.w.writen1(xtag)
+}
+
+func (e *simpleEncDriver) encodeArrayPreamble(length int) {
+	e.encLen(simpleVdArray, length)
+}
+
+func (e *simpleEncDriver) encodeMapPreamble(length int) {
+	e.encLen(simpleVdMap, length)
+}
+
+func (e *simpleEncDriver) encodeString(c charEncoding, v string) {
+	e.encLen(simpleVdString, len(v))
+	e.w.writestr(v)
+}
+
+func (e *simpleEncDriver) encodeSymbol(v string) {
+	e.encodeString(c_UTF8, v)
+}
+
+func (e *simpleEncDriver) encodeStringBytes(c charEncoding, v []byte) {
+	e.encLen(simpleVdByteArray, len(v))
+	e.w.writeb(v)
+}
+
+//------------------------------------
+
+type simpleDecDriver struct {
+	h      *SimpleHandle
+	r      decReader
+	bdRead bool
+	bdType valueType
+	bd     byte
+	//b      [8]byte
+}
+
+func (d *simpleDecDriver) initReadNext() {
+	if d.bdRead {
+		return
+	}
+	d.bd = d.r.readn1()
+	d.bdRead = true
+	d.bdType = valueTypeUnset
+}
+
+func (d *simpleDecDriver) currentEncodedType() valueType {
+	if d.bdType == valueTypeUnset {
+		switch d.bd {
+		case simpleVdNil:
+			d.bdType = valueTypeNil
+		case simpleVdTrue, simpleVdFalse:
+			d.bdType = valueTypeBool
+		case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
+			d.bdType = valueTypeUint
+		case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
+			d.bdType = valueTypeInt
+		case simpleVdFloat32, simpleVdFloat64:
+			d.bdType = valueTypeFloat
+		case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
+			d.bdType = valueTypeString
+		case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
+			d.bdType = valueTypeBytes
+		case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
+			d.bdType = valueTypeExt
+		case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4:
+			d.bdType = valueTypeArray
+		case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
+			d.bdType = valueTypeMap
+		default:
+			decErr("currentEncodedType: Unrecognized d.vd: 0x%x", d.bd)
+		}
+	}
+	return d.bdType
+}
+
+func (d *simpleDecDriver) tryDecodeAsNil() bool {
+	if d.bd == simpleVdNil {
+		d.bdRead = false
+		return true
+	}
+	return false
+}
+
+func (d *simpleDecDriver) isBuiltinType(rt uintptr) bool {
+	return false
+}
+
+func (d *simpleDecDriver) decodeBuiltin(rt uintptr, v interface{}) {
+}
+
+func (d *simpleDecDriver) decIntAny() (ui uint64, i int64, neg bool) {
+	switch d.bd {
+	case simpleVdPosInt:
+		ui = uint64(d.r.readn1())
+		i = int64(ui)
+	case simpleVdPosInt + 1:
+		ui = uint64(d.r.readUint16())
+		i = int64(ui)
+	case simpleVdPosInt + 2:
+		ui = uint64(d.r.readUint32())
+		i = int64(ui)
+	case simpleVdPosInt + 3:
+		ui = uint64(d.r.readUint64())
+		i = int64(ui)
+	case simpleVdNegInt:
+		ui = uint64(d.r.readn1())
+		i = -(int64(ui))
+		neg = true
+	case simpleVdNegInt + 1:
+		ui = uint64(d.r.readUint16())
+		i = -(int64(ui))
+		neg = true
+	case simpleVdNegInt + 2:
+		ui = uint64(d.r.readUint32())
+		i = -(int64(ui))
+		neg = true
+	case simpleVdNegInt + 3:
+		ui = uint64(d.r.readUint64())
+		i = -(int64(ui))
+		neg = true
+	default:
+		decErr("decIntAny: Integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd)
+	}
+	// don't do this check, because callers may only want the unsigned value.
+	// if ui > math.MaxInt64 {
+	// 	decErr("decIntAny: Integer out of range for signed int64: %v", ui)
+	// }
+	return
+}
+
+func (d *simpleDecDriver) decodeInt(bitsize uint8) (i int64) {
+	_, i, _ = d.decIntAny()
+	checkOverflow(0, i, bitsize)
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) decodeUint(bitsize uint8) (ui uint64) {
+	ui, i, neg := d.decIntAny()
+	if neg {
+		decErr("Assigning negative signed value: %v, to unsigned type", i)
+	}
+	checkOverflow(ui, 0, bitsize)
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) decodeFloat(chkOverflow32 bool) (f float64) {
+	switch d.bd {
+	case simpleVdFloat32:
+		f = float64(math.Float32frombits(d.r.readUint32()))
+	case simpleVdFloat64:
+		f = math.Float64frombits(d.r.readUint64())
+	default:
+		if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 {
+			_, i, _ := d.decIntAny()
+			f = float64(i)
+		} else {
+			decErr("Float only valid from float32/64: Invalid descriptor: %v", d.bd)
+		}
+	}
+	checkOverflowFloat32(f, chkOverflow32)
+	d.bdRead = false
+	return
+}
+
+// bool can be decoded from bool only (single byte).
+func (d *simpleDecDriver) decodeBool() (b bool) {
+	switch d.bd {
+	case simpleVdTrue:
+		b = true
+	case simpleVdFalse:
+	default:
+		decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) readMapLen() (length int) {
+	d.bdRead = false
+	return d.decLen()
+}
+
+func (d *simpleDecDriver) readArrayLen() (length int) {
+	d.bdRead = false
+	return d.decLen()
+}
+
+func (d *simpleDecDriver) decLen() int {
+	switch d.bd % 8 {
+	case 0:
+		return 0
+	case 1:
+		return int(d.r.readn1())
+	case 2:
+		return int(d.r.readUint16())
+	case 3:
+		ui := uint64(d.r.readUint32())
+		checkOverflow(ui, 0, intBitsize)
+		return int(ui)
+	case 4:
+		ui := d.r.readUint64()
+		checkOverflow(ui, 0, intBitsize)
+		return int(ui)
+	}
+	decErr("decLen: Cannot read length: bd%8 must be in range 0..4. Got: %d", d.bd%8)
+	return -1
+}
+
+func (d *simpleDecDriver) decodeString() (s string) {
+	s = string(d.r.readn(d.decLen()))
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) {
+	if clen := d.decLen(); clen > 0 {
+		// if no contents in stream, don't update the passed byteslice
+		if len(bs) != clen {
+			if len(bs) > clen {
+				bs = bs[:clen]
+			} else {
+				bs = make([]byte, clen)
+			}
+			bsOut = bs
+			changed = true
+		}
+		d.r.readb(bs)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) {
+	switch d.bd {
+	case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
+		l := d.decLen()
+		xtag = d.r.readn1()
+		if verifyTag && xtag != tag {
+			decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag)
+		}
+		xbs = d.r.readn(l)
+	case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
+		xbs, _ = d.decodeBytes(nil)
+	default:
+		decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd)
+	}
+	d.bdRead = false
+	return
+}
+
+func (d *simpleDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) {
+	d.initReadNext()
+
+	switch d.bd {
+	case simpleVdNil:
+		vt = valueTypeNil
+	case simpleVdFalse:
+		vt = valueTypeBool
+		v = false
+	case simpleVdTrue:
+		vt = valueTypeBool
+		v = true
+	case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
+		vt = valueTypeUint
+		ui, _, _ := d.decIntAny()
+		v = ui
+	case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
+		vt = valueTypeInt
+		_, i, _ := d.decIntAny()
+		v = i
+	case simpleVdFloat32:
+		vt = valueTypeFloat
+		v = d.decodeFloat(true)
+	case simpleVdFloat64:
+		vt = valueTypeFloat
+		v = d.decodeFloat(false)
+	case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
+		vt = valueTypeString
+		v = d.decodeString()
+	case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
+		vt = valueTypeBytes
+		v, _ = d.decodeBytes(nil)
+	case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
+		vt = valueTypeExt
+		l := d.decLen()
+		var re RawExt
+		re.Tag = d.r.readn1()
+		re.Data = d.r.readn(l)
+		v = &re
+		vt = valueTypeExt
+	case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4:
+		vt = valueTypeArray
+		decodeFurther = true
+	case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
+		vt = valueTypeMap
+		decodeFurther = true
+	default:
+		decErr("decodeNaked: Unrecognized d.vd: 0x%x", d.bd)
+	}
+
+	if !decodeFurther {
+		d.bdRead = false
+	}
+	return
+}
+
+//------------------------------------
+
+// SimpleHandle is a Handle for a very simple encoding format.
+//
+// simple is a simplistic codec similar to binc, but not as compact.
+//   - Encoding of a value is always preceeded by the descriptor byte (bd)
+//   - True, false, nil are encoded fully in 1 byte (the descriptor)
+//   - Integers (intXXX, uintXXX) are encoded in 1, 2, 4 or 8 bytes (plus a descriptor byte).
+//     There are positive (uintXXX and intXXX >= 0) and negative (intXXX < 0) integers.
+//   - Floats are encoded in 4 or 8 bytes (plus a descriptor byte)
+//   - Lenght of containers (strings, bytes, array, map, extensions)
+//     are encoded in 0, 1, 2, 4 or 8 bytes.
+//     Zero-length containers have no length encoded.
+//     For others, the number of bytes is given by pow(2, bd%3)
+//   - maps are encoded as [bd] [length] [[key][value]]...
+//   - arrays are encoded as [bd] [length] [value]...
+//   - extensions are encoded as [bd] [length] [tag] [byte]...
+//   - strings/bytearrays are encoded as [bd] [length] [byte]...
+//
+// The full spec will be published soon.
+type SimpleHandle struct {
+	BasicHandle
+}
+
+func (h *SimpleHandle) newEncDriver(w encWriter) encDriver {
+	return &simpleEncDriver{w: w, h: h}
+}
+
+func (h *SimpleHandle) newDecDriver(r decReader) decDriver {
+	return &simpleDecDriver{r: r, h: h}
+}
+
+func (_ *SimpleHandle) writeExt() bool {
+	return true
+}
+
+func (h *SimpleHandle) getBasicHandle() *BasicHandle {
+	return &h.BasicHandle
+}
+
+var _ decDriver = (*simpleDecDriver)(nil)
+var _ encDriver = (*simpleEncDriver)(nil)

+ 193 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/time.go

@@ -0,0 +1,193 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+import (
+	"time"
+)
+
+var (
+	timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
+)
+
+// EncodeTime encodes a time.Time as a []byte, including
+// information on the instant in time and UTC offset.
+//
+// Format Description
+//
+//   A timestamp is composed of 3 components:
+//
+//   - secs: signed integer representing seconds since unix epoch
+//   - nsces: unsigned integer representing fractional seconds as a
+//     nanosecond offset within secs, in the range 0 <= nsecs < 1e9
+//   - tz: signed integer representing timezone offset in minutes east of UTC,
+//     and a dst (daylight savings time) flag
+//
+//   When encoding a timestamp, the first byte is the descriptor, which
+//   defines which components are encoded and how many bytes are used to
+//   encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it
+//   is not encoded in the byte array explicitly*.
+//
+//       Descriptor 8 bits are of the form `A B C DDD EE`:
+//           A:   Is secs component encoded? 1 = true
+//           B:   Is nsecs component encoded? 1 = true
+//           C:   Is tz component encoded? 1 = true
+//           DDD: Number of extra bytes for secs (range 0-7).
+//                If A = 1, secs encoded in DDD+1 bytes.
+//                    If A = 0, secs is not encoded, and is assumed to be 0.
+//                    If A = 1, then we need at least 1 byte to encode secs.
+//                    DDD says the number of extra bytes beyond that 1.
+//                    E.g. if DDD=0, then secs is represented in 1 byte.
+//                         if DDD=2, then secs is represented in 3 bytes.
+//           EE:  Number of extra bytes for nsecs (range 0-3).
+//                If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above)
+//
+//   Following the descriptor bytes, subsequent bytes are:
+//
+//       secs component encoded in `DDD + 1` bytes (if A == 1)
+//       nsecs component encoded in `EE + 1` bytes (if B == 1)
+//       tz component encoded in 2 bytes (if C == 1)
+//
+//   secs and nsecs components are integers encoded in a BigEndian
+//   2-complement encoding format.
+//
+//   tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to
+//   Least significant bit 0 are described below:
+//
+//       Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes).
+//       Bit 15 = have\_dst: set to 1 if we set the dst flag.
+//       Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not.
+//       Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format.
+//
+func encodeTime(t time.Time) []byte {
+	//t := rv.Interface().(time.Time)
+	tsecs, tnsecs := t.Unix(), t.Nanosecond()
+	var (
+		bd   byte
+		btmp [8]byte
+		bs   [16]byte
+		i    int = 1
+	)
+	l := t.Location()
+	if l == time.UTC {
+		l = nil
+	}
+	if tsecs != 0 {
+		bd = bd | 0x80
+		bigen.PutUint64(btmp[:], uint64(tsecs))
+		f := pruneSignExt(btmp[:], tsecs >= 0)
+		bd = bd | (byte(7-f) << 2)
+		copy(bs[i:], btmp[f:])
+		i = i + (8 - f)
+	}
+	if tnsecs != 0 {
+		bd = bd | 0x40
+		bigen.PutUint32(btmp[:4], uint32(tnsecs))
+		f := pruneSignExt(btmp[:4], true)
+		bd = bd | byte(3-f)
+		copy(bs[i:], btmp[f:4])
+		i = i + (4 - f)
+	}
+	if l != nil {
+		bd = bd | 0x20
+		// Note that Go Libs do not give access to dst flag.
+		_, zoneOffset := t.Zone()
+		//zoneName, zoneOffset := t.Zone()
+		zoneOffset /= 60
+		z := uint16(zoneOffset)
+		bigen.PutUint16(btmp[:2], z)
+		// clear dst flags
+		bs[i] = btmp[0] & 0x3f
+		bs[i+1] = btmp[1]
+		i = i + 2
+	}
+	bs[0] = bd
+	return bs[0:i]
+}
+
+// DecodeTime decodes a []byte into a time.Time.
+func decodeTime(bs []byte) (tt time.Time, err error) {
+	bd := bs[0]
+	var (
+		tsec  int64
+		tnsec uint32
+		tz    uint16
+		i     byte = 1
+		i2    byte
+		n     byte
+	)
+	if bd&(1<<7) != 0 {
+		var btmp [8]byte
+		n = ((bd >> 2) & 0x7) + 1
+		i2 = i + n
+		copy(btmp[8-n:], bs[i:i2])
+		//if first bit of bs[i] is set, then fill btmp[0..8-n] with 0xff (ie sign extend it)
+		if bs[i]&(1<<7) != 0 {
+			copy(btmp[0:8-n], bsAll0xff)
+			//for j,k := byte(0), 8-n; j < k; j++ {	btmp[j] = 0xff }
+		}
+		i = i2
+		tsec = int64(bigen.Uint64(btmp[:]))
+	}
+	if bd&(1<<6) != 0 {
+		var btmp [4]byte
+		n = (bd & 0x3) + 1
+		i2 = i + n
+		copy(btmp[4-n:], bs[i:i2])
+		i = i2
+		tnsec = bigen.Uint32(btmp[:])
+	}
+	if bd&(1<<5) == 0 {
+		tt = time.Unix(tsec, int64(tnsec)).UTC()
+		return
+	}
+	// In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name.
+	// However, we need name here, so it can be shown when time is printed.
+	// Zone name is in form: UTC-08:00.
+	// Note that Go Libs do not give access to dst flag, so we ignore dst bits
+
+	i2 = i + 2
+	tz = bigen.Uint16(bs[i:i2])
+	i = i2
+	// sign extend sign bit into top 2 MSB (which were dst bits):
+	if tz&(1<<13) == 0 { // positive
+		tz = tz & 0x3fff //clear 2 MSBs: dst bits
+	} else { // negative
+		tz = tz | 0xc000 //set 2 MSBs: dst bits
+		//tzname[3] = '-' (TODO: verify. this works here)
+	}
+	tzint := int16(tz)
+	if tzint == 0 {
+		tt = time.Unix(tsec, int64(tnsec)).UTC()
+	} else {
+		// For Go Time, do not use a descriptive timezone.
+		// It's unnecessary, and makes it harder to do a reflect.DeepEqual.
+		// The Offset already tells what the offset should be, if not on UTC and unknown zone name.
+		// var zoneName = timeLocUTCName(tzint)
+		tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone("", int(tzint)*60))
+	}
+	return
+}
+
+func timeLocUTCName(tzint int16) string {
+	if tzint == 0 {
+		return "UTC"
+	}
+	var tzname = []byte("UTC+00:00")
+	//tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below.
+	//tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first
+	var tzhr, tzmin int16
+	if tzint < 0 {
+		tzname[3] = '-' // (TODO: verify. this works here)
+		tzhr, tzmin = -tzint/60, (-tzint)%60
+	} else {
+		tzhr, tzmin = tzint/60, tzint%60
+	}
+	tzname[4] = timeDigits[tzhr/10]
+	tzname[5] = timeDigits[tzhr%10]
+	tzname[7] = timeDigits[tzmin/10]
+	tzname[8] = timeDigits[tzmin%10]
+	return string(tzname)
+	//return time.FixedZone(string(tzname), int(tzint)*60)
+}

+ 103 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/go-msgpack/codec/z_helper_test.go

@@ -0,0 +1,103 @@
+// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved.
+// Use of this source code is governed by a BSD-style license found in the LICENSE file.
+
+package codec
+
+// All non-std package dependencies related to testing live in this file,
+// so porting to different environment is easy (just update functions).
+//
+// Also, this file is called z_helper_test, to give a "hint" to compiler
+// that its init() function should be called last. (not guaranteed by spec)
+
+import (
+	"errors"
+	"reflect"
+	"flag"
+	"testing"
+)
+
+var (
+	testLogToT    = true
+	failNowOnFail = true
+)
+
+func init() {
+	testInitFlags()
+	benchInitFlags()
+	flag.Parse()
+	testInit()
+	benchInit()
+}
+
+func checkErrT(t *testing.T, err error) {
+	if err != nil {
+		logT(t, err.Error())
+		failT(t)
+	}
+}
+
+func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}, desc string) (err error) {
+	if err = deepEqual(v1, v2); err != nil {
+		logT(t, "Not Equal: %s: %v. v1: %v, v2: %v", desc, err, v1, v2)
+		failT(t)
+	}
+	return
+}
+
+func logT(x interface{}, format string, args ...interface{}) {
+	if t, ok := x.(*testing.T); ok && t != nil && testLogToT {
+		t.Logf(format, args...)
+	} else if b, ok := x.(*testing.B); ok && b != nil && testLogToT {
+		b.Logf(format, args...)
+	} else {
+		debugf(format, args...)
+	}
+}
+
+func failT(t *testing.T) {
+	if failNowOnFail {
+		t.FailNow()
+	} else {
+		t.Fail()
+	}
+}
+
+func deepEqual(v1, v2 interface{}) (err error) {
+	if !reflect.DeepEqual(v1, v2) {
+		err = errors.New("Not Match")
+	}
+	return
+}
+
+func approxDataSize(rv reflect.Value) (sum int) {
+	switch rk := rv.Kind(); rk {
+	case reflect.Invalid:
+	case reflect.Ptr, reflect.Interface:
+		sum += int(rv.Type().Size())
+		sum += approxDataSize(rv.Elem())
+	case reflect.Slice:
+		sum += int(rv.Type().Size())
+		for j := 0; j < rv.Len(); j++ {
+			sum += approxDataSize(rv.Index(j))
+		}
+	case reflect.String:
+		sum += int(rv.Type().Size())
+		sum += rv.Len()
+	case reflect.Map:
+		sum += int(rv.Type().Size())
+		for _, mk := range rv.MapKeys() {
+			sum += approxDataSize(mk)
+			sum += approxDataSize(rv.MapIndex(mk))
+		}
+	case reflect.Struct:
+		//struct size already includes the full data size.
+		//sum += int(rv.Type().Size())
+		for j := 0; j < rv.NumField(); j++ {
+			sum += approxDataSize(rv.Field(j))
+		}
+	default:
+		//pure value types
+		sum += int(rv.Type().Size())
+	}
+	return
+}

+ 25 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/.gitignore

@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+.vagrant/
+

+ 354 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/LICENSE

@@ -0,0 +1,354 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributor”
+
+     means each individual or legal entity that creates, contributes to the
+     creation of, or owns Covered Software.
+
+1.2. “Contributor Version”
+
+     means the combination of the Contributions of others (if any) used by a
+     Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contribution”
+
+     means Covered Software of a particular Contributor.
+
+1.4. “Covered Software”
+
+     means Source Code Form to which the initial Contributor has attached the
+     notice in Exhibit A, the Executable Form of such Source Code Form, and
+     Modifications of such Source Code Form, in each case including portions
+     thereof.
+
+1.5. “Incompatible With Secondary Licenses”
+     means
+
+     a. that the initial Contributor has attached the notice described in
+        Exhibit B to the Covered Software; or
+
+     b. that the Covered Software was made available under the terms of version
+        1.1 or earlier of the License, but not also under the terms of a
+        Secondary License.
+
+1.6. “Executable Form”
+
+     means any form of the work other than Source Code Form.
+
+1.7. “Larger Work”
+
+     means a work that combines Covered Software with other material, in a separate
+     file or files, that is not Covered Software.
+
+1.8. “License”
+
+     means this document.
+
+1.9. “Licensable”
+
+     means having the right to grant, to the maximum extent possible, whether at the
+     time of the initial grant or subsequently, any and all of the rights conveyed by
+     this License.
+
+1.10. “Modifications”
+
+     means any of the following:
+
+     a. any file in Source Code Form that results from an addition to, deletion
+        from, or modification of the contents of Covered Software; or
+
+     b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims” of a Contributor
+
+      means any patent claim(s), including without limitation, method, process,
+      and apparatus claims, in any patent Licensable by such Contributor that
+      would be infringed, but for the grant of the License, by the making,
+      using, selling, offering for sale, having made, import, or transfer of
+      either its Contributions or its Contributor Version.
+
+1.12. “Secondary License”
+
+      means either the GNU General Public License, Version 2.0, the GNU Lesser
+      General Public License, Version 2.1, the GNU Affero General Public
+      License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Form”
+
+      means the form of the work preferred for making modifications.
+
+1.14. “You” (or “Your”)
+
+      means an individual or a legal entity exercising rights under this
+      License. For legal entities, “You” includes any entity that controls, is
+      controlled by, or is under common control with You. For purposes of this
+      definition, “control” means (a) the power, direct or indirect, to cause
+      the direction or management of such entity, whether by contract or
+      otherwise, or (b) ownership of more than fifty percent (50%) of the
+      outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+     Each Contributor hereby grants You a world-wide, royalty-free,
+     non-exclusive license:
+
+     a. under intellectual property rights (other than patent or trademark)
+        Licensable by such Contributor to use, reproduce, make available,
+        modify, display, perform, distribute, and otherwise exploit its
+        Contributions, either on an unmodified basis, with Modifications, or as
+        part of a Larger Work; and
+
+     b. under Patent Claims of such Contributor to make, use, sell, offer for
+        sale, have made, import, and otherwise transfer either its Contributions
+        or its Contributor Version.
+
+2.2. Effective Date
+
+     The licenses granted in Section 2.1 with respect to any Contribution become
+     effective for each Contribution on the date the Contributor first distributes
+     such Contribution.
+
+2.3. Limitations on Grant Scope
+
+     The licenses granted in this Section 2 are the only rights granted under this
+     License. No additional rights or licenses will be implied from the distribution
+     or licensing of Covered Software under this License. Notwithstanding Section
+     2.1(b) above, no patent license is granted by a Contributor:
+
+     a. for any code that a Contributor has removed from Covered Software; or
+
+     b. for infringements caused by: (i) Your and any other third party’s
+        modifications of Covered Software, or (ii) the combination of its
+        Contributions with other software (except as part of its Contributor
+        Version); or
+
+     c. under Patent Claims infringed by Covered Software in the absence of its
+        Contributions.
+
+     This License does not grant any rights in the trademarks, service marks, or
+     logos of any Contributor (except as may be necessary to comply with the
+     notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+     No Contributor makes additional grants as a result of Your choice to
+     distribute the Covered Software under a subsequent version of this License
+     (see Section 10.2) or under the terms of a Secondary License (if permitted
+     under the terms of Section 3.3).
+
+2.5. Representation
+
+     Each Contributor represents that the Contributor believes its Contributions
+     are its original creation(s) or it has sufficient rights to grant the
+     rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+     This License is not intended to limit any rights You have under applicable
+     copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+     Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+     Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+     All distribution of Covered Software in Source Code Form, including any
+     Modifications that You create or to which You contribute, must be under the
+     terms of this License. You must inform recipients that the Source Code Form
+     of the Covered Software is governed by the terms of this License, and how
+     they can obtain a copy of this License. You may not attempt to alter or
+     restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+     If You distribute Covered Software in Executable Form then:
+
+     a. such Covered Software must also be made available in Source Code Form,
+        as described in Section 3.1, and You must inform recipients of the
+        Executable Form how they can obtain a copy of such Source Code Form by
+        reasonable means in a timely manner, at a charge no more than the cost
+        of distribution to the recipient; and
+
+     b. You may distribute such Executable Form under the terms of this License,
+        or sublicense it under different terms, provided that the license for
+        the Executable Form does not attempt to limit or alter the recipients’
+        rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+     You may create and distribute a Larger Work under terms of Your choice,
+     provided that You also comply with the requirements of this License for the
+     Covered Software. If the Larger Work is a combination of Covered Software
+     with a work governed by one or more Secondary Licenses, and the Covered
+     Software is not Incompatible With Secondary Licenses, this License permits
+     You to additionally distribute such Covered Software under the terms of
+     such Secondary License(s), so that the recipient of the Larger Work may, at
+     their option, further distribute the Covered Software under the terms of
+     either this License or such Secondary License(s).
+
+3.4. Notices
+
+     You may not remove or alter the substance of any license notices (including
+     copyright notices, patent notices, disclaimers of warranty, or limitations
+     of liability) contained within the Source Code Form of the Covered
+     Software, except that You may alter any license notices to the extent
+     required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+     You may choose to offer, and to charge a fee for, warranty, support,
+     indemnity or liability obligations to one or more recipients of Covered
+     Software. However, You may do so only on Your own behalf, and not on behalf
+     of any Contributor. You must make it absolutely clear that any such
+     warranty, support, indemnity, or liability obligation is offered by You
+     alone, and You hereby agree to indemnify every Contributor for any
+     liability incurred by such Contributor as a result of warranty, support,
+     indemnity or liability terms You offer. You may include additional
+     disclaimers of warranty and limitations of liability specific to any
+     jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+   If it is impossible for You to comply with any of the terms of this License
+   with respect to some or all of the Covered Software due to statute, judicial
+   order, or regulation then You must: (a) comply with the terms of this License
+   to the maximum extent possible; and (b) describe the limitations and the code
+   they affect. Such description must be placed in a text file included with all
+   distributions of the Covered Software under this License. Except to the
+   extent prohibited by statute or regulation, such description must be
+   sufficiently detailed for a recipient of ordinary skill to be able to
+   understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+     fail to comply with any of its terms. However, if You become compliant,
+     then the rights granted under this License from a particular Contributor
+     are reinstated (a) provisionally, unless and until such Contributor
+     explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+     if such Contributor fails to notify You of the non-compliance by some
+     reasonable means prior to 60 days after You have come back into compliance.
+     Moreover, Your grants from a particular Contributor are reinstated on an
+     ongoing basis if such Contributor notifies You of the non-compliance by
+     some reasonable means, this is the first time You have received notice of
+     non-compliance with this License from such Contributor, and You become
+     compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+     infringement claim (excluding declaratory judgment actions, counter-claims,
+     and cross-claims) alleging that a Contributor Version directly or
+     indirectly infringes any patent, then the rights granted to You by any and
+     all Contributors for the Covered Software under Section 2.1 of this License
+     shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+     license agreements (excluding distributors and resellers) which have been
+     validly granted by You or Your distributors under this License prior to
+     termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+   Covered Software is provided under this License on an “as is” basis, without
+   warranty of any kind, either expressed, implied, or statutory, including,
+   without limitation, warranties that the Covered Software is free of defects,
+   merchantable, fit for a particular purpose or non-infringing. The entire
+   risk as to the quality and performance of the Covered Software is with You.
+   Should any Covered Software prove defective in any respect, You (not any
+   Contributor) assume the cost of any necessary servicing, repair, or
+   correction. This disclaimer of warranty constitutes an essential part of this
+   License. No use of  any Covered Software is authorized under this License
+   except under this disclaimer.
+
+7. Limitation of Liability
+
+   Under no circumstances and under no legal theory, whether tort (including
+   negligence), contract, or otherwise, shall any Contributor, or anyone who
+   distributes Covered Software as permitted above, be liable to You for any
+   direct, indirect, special, incidental, or consequential damages of any
+   character including, without limitation, damages for lost profits, loss of
+   goodwill, work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses, even if such party shall have been
+   informed of the possibility of such damages. This limitation of liability
+   shall not apply to liability for death or personal injury resulting from such
+   party’s negligence to the extent applicable law prohibits such limitation.
+   Some jurisdictions do not allow the exclusion or limitation of incidental or
+   consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+   Any litigation relating to this License may be brought only in the courts of
+   a jurisdiction where the defendant maintains its principal place of business
+   and such litigation shall be governed by laws of that jurisdiction, without
+   reference to its conflict-of-law provisions. Nothing in this Section shall
+   prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+   This License represents the complete agreement concerning the subject matter
+   hereof. If any provision of this License is held to be unenforceable, such
+   provision shall be reformed only to the extent necessary to make it
+   enforceable. Any law or regulation which provides that the language of a
+   contract shall be construed against the drafter shall not be used to construe
+   this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+      Mozilla Foundation is the license steward. Except as provided in Section
+      10.3, no one other than the license steward has the right to modify or
+      publish new versions of this License. Each version will be given a
+      distinguishing version number.
+
+10.2. Effect of New Versions
+
+      You may distribute the Covered Software under the terms of the version of
+      the License under which You originally received the Covered Software, or
+      under the terms of any subsequent version published by the license
+      steward.
+
+10.3. Modified Versions
+
+      If you create software not governed by this License, and you want to
+      create a new license for such software, you may create and use a modified
+      version of this License if you rename the license and remove any
+      references to the name of the license steward (except to note that such
+      modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+      If You choose to distribute Source Code Form that is Incompatible With
+      Secondary Licenses under the terms of this version of the License, the
+      notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+      This Source Code Form is subject to the
+      terms of the Mozilla Public License, v.
+      2.0. If a copy of the MPL was not
+      distributed with this file, You can
+      obtain one at
+      http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+      This Source Code Form is “Incompatible
+      With Secondary Licenses”, as defined by
+      the Mozilla Public License, v. 2.0.
+

+ 14 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/Makefile

@@ -0,0 +1,14 @@
+test: subnet
+	go test ./...
+
+integ: subnet
+	INTEG_TESTS=yes go test ./...
+
+subnet:
+	./test/setup_subnet.sh
+
+cov:
+	gocov test github.com/hashicorp/memberlist | gocov-html > /tmp/coverage.html
+	open /tmp/coverage.html
+
+.PNONY: test cov integ

+ 137 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/README.md

@@ -0,0 +1,137 @@
+# memberlist
+
+memberlist is a [Go](http://www.golang.org) library that manages cluster
+membership and member failure detection using a gossip based protocol.
+
+The use cases for such a library are far-reaching: all distributed systems
+require membership, and memberlist is a re-usable solution to managing
+cluster membership and node failure detection.
+
+memberlist is eventually consistent but converges quickly on average.
+The speed at which it converges can be heavily tuned via various knobs
+on the protocol. Node failures are detected and network partitions are partially
+tolerated by attempting to communicate to potentially dead nodes through
+multiple routes.
+
+## Building
+
+If you wish to build memberlist you'll need Go version 1.2+ installed.
+
+Please check your installation with:
+
+```
+go version
+```
+
+## Usage
+
+Memberlist is surprisingly simple to use. An example is shown below:
+
+```go
+/* Create the initial memberlist from a safe configuration.
+   Please reference the godoc for other default config types.
+   http://godoc.org/github.com/hashicorp/memberlist#Config
+*/
+list, err := memberlist.Create(memberlist.DefaultLocalConfig())
+if err != nil {
+	panic("Failed to create memberlist: " + err.Error())
+}
+
+// Join an existing cluster by specifying at least one known member.
+n, err := list.Join([]string{"1.2.3.4"})
+if err != nil {
+	panic("Failed to join cluster: " + err.Error())
+}
+
+// Ask for members of the cluster
+for _, member := range list.Members() {
+	fmt.Printf("Member: %s %s\n", member.Name, member.Addr)
+}
+
+// Continue doing whatever you need, memberlist will maintain membership
+// information in the background. Delegates can be used for receiving
+// events when members join or leave.
+```
+
+The most difficult part of memberlist is configuring it since it has many
+available knobs in order to tune state propagation delay and convergence times.
+Memberlist provides a default configuration that offers a good starting point,
+but errs on the side of caution, choosing values that are optimized for
+higher convergence at the cost of higher bandwidth usage.
+
+For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/memberlist).
+
+## Protocol
+
+memberlist is based on ["SWIM: Scalable Weakly-consistent Infection-style Process Group Membership Protocol"](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf),
+with a few minor adaptations, mostly to increase propogation speed and
+convergence rate.
+
+A high level overview of the memberlist protocol (based on SWIM) is
+described below, but for details please read the full
+[SWIM paper](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf)
+followed by the memberlist source. We welcome any questions related
+to the protocol on our issue tracker.
+
+### Protocol Description
+
+memberlist begins by joining an existing cluster or starting a new
+cluster. If starting a new cluster, additional nodes are expected to join
+it. New nodes in an existing cluster must be given the address of at
+least one existing member in order to join the cluster. The new member
+does a full state sync with the existing member over TCP and begins gossiping its
+existence to the cluster.
+
+Gossip is done over UDP to a with a configurable but fixed fanout and interval.
+This ensures that network usage is constant with regards to number of nodes, as opposed to
+exponential growth that can occur with traditional heartbeat mechanisms.
+Complete state exchanges with a random node are done periodically over
+TCP, but much less often than gossip messages. This increases the likelihood
+that the membership list converges properly since the full state is exchanged
+and merged. The interval between full state exchanges is configurable or can
+be disabled entirely.
+
+Failure detection is done by periodic random probing using a configurable interval.
+If the node fails to ack within a reasonable time (typically some multiple
+of RTT), then an indirect probe is attempted. An indirect probe asks a
+configurable number of random nodes to probe the same node, in case there
+are network issues causing our own node to fail the probe. If both our
+probe and the indirect probes fail within a reasonable time, then the
+node is marked "suspicious" and this knowledge is gossiped to the cluster.
+A suspicious node is still considered a member of cluster. If the suspect member
+of the cluster does not disputes the suspicion within a configurable period of
+time, the node is finally considered dead, and this state is then gossiped
+to the cluster.
+
+This is a brief and incomplete description of the protocol. For a better idea,
+please read the
+[SWIM paper](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf)
+in its entirety, along with the memberlist source code.
+
+### Changes from SWIM
+
+As mentioned earlier, the memberlist protocol is based on SWIM but includes
+minor changes, mostly to increase propogation speed and convergence rates.
+
+The changes from SWIM are noted here:
+
+* memberlist does a full state sync over TCP periodically. SWIM only propagates
+  changes over gossip. While both eventually reach convergence, the full state
+  sync increases the likelihood that nodes are fully converged more quickly,
+  at the expense of more bandwidth usage. This feature can be totally disabled
+  if you wish.
+
+* memberlist has a dedicated gossip layer separate from the failure detection
+  protocol. SWIM only piggybacks gossip messages on top of probe/ack messages.
+  memberlist also piggybacks gossip messages on top of probe/ack messages, but
+  also will periodically send out dedicated gossip messages on their own. This
+  feature lets you have a higher gossip rate (for example once per 200ms)
+  and a slower failure detection rate (such as once per second), resulting
+  in overall faster convergence rates and data propogation speeds. This feature
+  can be totally disabed as well, if you wish.
+
+* memberlist stores around the state of dead nodes for a set amount of time,
+  so that when full syncs are requested, the requester also receives information
+  about dead nodes. Because SWIM doesn't do full syncs, SWIM deletes dead node
+  state immediately upon learning that the node is dead. This change again helps
+  the cluster converge more quickly.

+ 100 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/broadcast.go

@@ -0,0 +1,100 @@
+package memberlist
+
+/*
+The broadcast mechanism works by maintaining a sorted list of messages to be
+sent out. When a message is to be broadcast, the retransmit count
+is set to zero and appended to the queue. The retransmit count serves
+as the "priority", ensuring that newer messages get sent first. Once
+a message hits the retransmit limit, it is removed from the queue.
+
+Additionally, older entries can be invalidated by new messages that
+are contradictory. For example, if we send "{suspect M1 inc: 1},
+then a following {alive M1 inc: 2} will invalidate that message
+*/
+
+type memberlistBroadcast struct {
+	node   string
+	msg    []byte
+	notify chan struct{}
+}
+
+func (b *memberlistBroadcast) Invalidates(other Broadcast) bool {
+	// Check if that broadcast is a memberlist type
+	mb, ok := other.(*memberlistBroadcast)
+	if !ok {
+		return false
+	}
+
+	// Invalidates any message about the same node
+	return b.node == mb.node
+}
+
+func (b *memberlistBroadcast) Message() []byte {
+	return b.msg
+}
+
+func (b *memberlistBroadcast) Finished() {
+	select {
+	case b.notify <- struct{}{}:
+	default:
+	}
+}
+
+// encodeAndBroadcast encodes a message and enqueues it for broadcast. Fails
+// silently if there is an encoding error.
+func (m *Memberlist) encodeAndBroadcast(node string, msgType messageType, msg interface{}) {
+	m.encodeBroadcastNotify(node, msgType, msg, nil)
+}
+
+// encodeBroadcastNotify encodes a message and enqueues it for broadcast
+// and notifies the given channel when transmission is finished. Fails
+// silently if there is an encoding error.
+func (m *Memberlist) encodeBroadcastNotify(node string, msgType messageType, msg interface{}, notify chan struct{}) {
+	buf, err := encode(msgType, msg)
+	if err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to encode message for broadcast: %s", err)
+	} else {
+		m.queueBroadcast(node, buf.Bytes(), notify)
+	}
+}
+
+// queueBroadcast is used to start dissemination of a message. It will be
+// sent up to a configured number of times. The message could potentially
+// be invalidated by a future message about the same node
+func (m *Memberlist) queueBroadcast(node string, msg []byte, notify chan struct{}) {
+	b := &memberlistBroadcast{node, msg, notify}
+	m.broadcasts.QueueBroadcast(b)
+}
+
+// getBroadcasts is used to return a slice of broadcasts to send up to
+// a maximum byte size, while imposing a per-broadcast overhead. This is used
+// to fill a UDP packet with piggybacked data
+func (m *Memberlist) getBroadcasts(overhead, limit int) [][]byte {
+	// Get memberlist messages first
+	toSend := m.broadcasts.GetBroadcasts(overhead, limit)
+
+	// Check if the user has anything to broadcast
+	d := m.config.Delegate
+	if d != nil {
+		// Determine the bytes used already
+		bytesUsed := 0
+		for _, msg := range toSend {
+			bytesUsed += len(msg) + overhead
+		}
+
+		// Check space remaining for user messages
+		avail := limit - bytesUsed
+		if avail > overhead+userMsgOverhead {
+			userMsgs := d.GetBroadcasts(overhead+userMsgOverhead, avail)
+
+			// Frame each user message
+			for _, msg := range userMsgs {
+				buf := make([]byte, 1, len(msg)+1)
+				buf[0] = byte(userMsg)
+				buf = append(buf, msg...)
+				toSend = append(toSend, buf)
+			}
+		}
+	}
+	return toSend
+}

+ 27 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/broadcast_test.go

@@ -0,0 +1,27 @@
+package memberlist
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestMemberlistBroadcast_Invalidates(t *testing.T) {
+	m1 := &memberlistBroadcast{"test", nil, nil}
+	m2 := &memberlistBroadcast{"foo", nil, nil}
+
+	if m1.Invalidates(m2) || m2.Invalidates(m1) {
+		t.Fatalf("unexpected invalidation")
+	}
+
+	if !m1.Invalidates(m1) {
+		t.Fatalf("expected invalidation")
+	}
+}
+
+func TestMemberlistBroadcast_Message(t *testing.T) {
+	m1 := &memberlistBroadcast{"test", []byte("test"), nil}
+	msg := m1.Message()
+	if !reflect.DeepEqual(msg, []byte("test")) {
+		t.Fatalf("messages do not match")
+	}
+}

+ 209 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/config.go

@@ -0,0 +1,209 @@
+package memberlist
+
+import (
+	"io"
+	"os"
+	"time"
+)
+
+type Config struct {
+	// The name of this node. This must be unique in the cluster.
+	Name string
+
+	// Configuration related to what address to bind to and ports to
+	// listen on. The port is used for both UDP and TCP gossip.
+	// It is assumed other nodes are running on this port, but they
+	// do not need to.
+	BindAddr string
+	BindPort int
+
+	// Configuration related to what address to advertise to other
+	// cluster members. Used for nat traversal.
+	AdvertiseAddr string
+	AdvertisePort int
+
+	// ProtocolVersion is the configured protocol version that we
+	// will _speak_. This must be between ProtocolVersionMin and
+	// ProtocolVersionMax.
+	ProtocolVersion uint8
+
+	// TCPTimeout is the timeout for establishing a TCP connection with
+	// a remote node for a full state sync.
+	TCPTimeout time.Duration
+
+	// IndirectChecks is the number of nodes that will be asked to perform
+	// an indirect probe of a node in the case a direct probe fails. Memberlist
+	// waits for an ack from any single indirect node, so increasing this
+	// number will increase the likelihood that an indirect probe will succeed
+	// at the expense of bandwidth.
+	IndirectChecks int
+
+	// RetransmitMult is the multiplier for the number of retransmissions
+	// that are attempted for messages broadcasted over gossip. The actual
+	// count of retransmissions is calculated using the formula:
+	//
+	//   Retransmits = RetransmitMult * log(N+1)
+	//
+	// This allows the retransmits to scale properly with cluster size. The
+	// higher the multiplier, the more likely a failed broadcast is to converge
+	// at the expense of increased bandwidth.
+	RetransmitMult int
+
+	// SuspicionMult is the multiplier for determining the time an
+	// inaccessible node is considered suspect before declaring it dead.
+	// The actual timeout is calculated using the formula:
+	//
+	//   SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval
+	//
+	// This allows the timeout to scale properly with expected propagation
+	// delay with a larger cluster size. The higher the multiplier, the longer
+	// an inaccessible node is considered part of the cluster before declaring
+	// it dead, giving that suspect node more time to refute if it is indeed
+	// still alive.
+	SuspicionMult int
+
+	// PushPullInterval is the interval between complete state syncs.
+	// Complete state syncs are done with a single node over TCP and are
+	// quite expensive relative to standard gossiped messages. Setting this
+	// to zero will disable state push/pull syncs completely.
+	//
+	// Setting this interval lower (more frequent) will increase convergence
+	// speeds across larger clusters at the expense of increased bandwidth
+	// usage.
+	PushPullInterval time.Duration
+
+	// ProbeInterval and ProbeTimeout are used to configure probing
+	// behavior for memberlist.
+	//
+	// ProbeInterval is the interval between random node probes. Setting
+	// this lower (more frequent) will cause the memberlist cluster to detect
+	// failed nodes more quickly at the expense of increased bandwidth usage.
+	//
+	// ProbeTimeout is the timeout to wait for an ack from a probed node
+	// before assuming it is unhealthy. This should be set to 99-percentile
+	// of RTT (round-trip time) on your network.
+	ProbeInterval time.Duration
+	ProbeTimeout  time.Duration
+
+	// GossipInterval and GossipNodes are used to configure the gossip
+	// behavior of memberlist.
+	//
+	// GossipInterval is the interval between sending messages that need
+	// to be gossiped that haven't been able to piggyback on probing messages.
+	// If this is set to zero, non-piggyback gossip is disabled. By lowering
+	// this value (more frequent) gossip messages are propagated across
+	// the cluster more quickly at the expense of increased bandwidth.
+	//
+	// GossipNodes is the number of random nodes to send gossip messages to
+	// per GossipInterval. Increasing this number causes the gossip messages
+	// to propagate across the cluster more quickly at the expense of
+	// increased bandwidth.
+	GossipInterval time.Duration
+	GossipNodes    int
+
+	// EnableCompression is used to control message compression. This can
+	// be used to reduce bandwidth usage at the cost of slightly more CPU
+	// utilization. This is only available starting at protocol version 1.
+	EnableCompression bool
+
+	// SecretKey is used to initialize the primary encryption key in a keyring.
+	// The primary encryption key is the only key used to encrypt messages and
+	// the first key used while attempting to decrypt messages. Providing a
+	// value for this primary key will enable message-level encryption and
+	// verification, and automatically install the key onto the keyring.
+	SecretKey []byte
+
+	// The keyring holds all of the encryption keys used internally. It is
+	// automatically initialized using the SecretKey and SecretKeys values.
+	Keyring *Keyring
+
+	// Delegate and Events are delegates for receiving and providing
+	// data to memberlist via callback mechanisms. For Delegate, see
+	// the Delegate interface. For Events, see the EventDelegate interface.
+	//
+	// The DelegateProtocolMin/Max are used to guarantee protocol-compatibility
+	// for any custom messages that the delegate might do (broadcasts,
+	// local/remote state, etc.). If you don't set these, then the protocol
+	// versions will just be zero, and version compliance won't be done.
+	Delegate                Delegate
+	DelegateProtocolVersion uint8
+	DelegateProtocolMin     uint8
+	DelegateProtocolMax     uint8
+	Events                  EventDelegate
+	Conflict                ConflictDelegate
+	Merge                   MergeDelegate
+
+	// LogOutput is the writer where logs should be sent. If this is not
+	// set, logging will go to stderr by default.
+	LogOutput io.Writer
+}
+
+// DefaultLANConfig returns a sane set of configurations for Memberlist.
+// It uses the hostname as the node name, and otherwise sets very conservative
+// values that are sane for most LAN environments. The default configuration
+// errs on the side on the side of caution, choosing values that are optimized
+// for higher convergence at the cost of higher bandwidth usage. Regardless,
+// these values are a good starting point when getting started with memberlist.
+func DefaultLANConfig() *Config {
+	hostname, _ := os.Hostname()
+	return &Config{
+		Name:             hostname,
+		BindAddr:         "0.0.0.0",
+		BindPort:         7946,
+		AdvertiseAddr:    "",
+		AdvertisePort:    7946,
+		ProtocolVersion:  ProtocolVersionMax,
+		TCPTimeout:       10 * time.Second,       // Timeout after 10 seconds
+		IndirectChecks:   3,                      // Use 3 nodes for the indirect ping
+		RetransmitMult:   4,                      // Retransmit a message 4 * log(N+1) nodes
+		SuspicionMult:    5,                      // Suspect a node for 5 * log(N+1) * Interval
+		PushPullInterval: 30 * time.Second,       // Low frequency
+		ProbeTimeout:     500 * time.Millisecond, // Reasonable RTT time for LAN
+		ProbeInterval:    1 * time.Second,        // Failure check every second
+
+		GossipNodes:    3,                      // Gossip to 3 nodes
+		GossipInterval: 200 * time.Millisecond, // Gossip more rapidly
+
+		EnableCompression: true, // Enable compression by default
+
+		SecretKey: nil,
+
+		Keyring: nil,
+	}
+}
+
+// DefaultWANConfig works like DefaultConfig, however it returns a configuration
+// that is optimized for most WAN environments. The default configuration is
+// still very conservative and errs on the side of caution.
+func DefaultWANConfig() *Config {
+	conf := DefaultLANConfig()
+	conf.TCPTimeout = 30 * time.Second
+	conf.SuspicionMult = 6
+	conf.PushPullInterval = 60 * time.Second
+	conf.ProbeTimeout = 3 * time.Second
+	conf.ProbeInterval = 5 * time.Second
+	conf.GossipNodes = 4 // Gossip less frequently, but to an additional node
+	conf.GossipInterval = 500 * time.Millisecond
+	return conf
+}
+
+// DefaultLocalConfig works like DefaultConfig, however it returns a configuration
+// that is optimized for a local loopback environments. The default configuration is
+// still very conservative and errs on the side of caution.
+func DefaultLocalConfig() *Config {
+	conf := DefaultLANConfig()
+	conf.TCPTimeout = time.Second
+	conf.IndirectChecks = 1
+	conf.RetransmitMult = 2
+	conf.SuspicionMult = 3
+	conf.PushPullInterval = 15 * time.Second
+	conf.ProbeTimeout = 200 * time.Millisecond
+	conf.ProbeInterval = time.Second
+	conf.GossipInterval = 100 * time.Millisecond
+	return conf
+}
+
+// Returns whether or not encryption is enabled
+func (c *Config) EncryptionEnabled() bool {
+	return c.Keyring != nil && len(c.Keyring.GetKeys()) > 0
+}

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/conflict_delegate.go

@@ -0,0 +1,10 @@
+package memberlist
+
+// ConflictDelegate is a used to inform a client that
+// a node has attempted to join which would result in a
+// name conflict. This happens if two clients are configured
+// with the same name but different addresses.
+type ConflictDelegate interface {
+	// NotifyConflict is invoked when a name conflict is detected
+	NotifyConflict(existing, other *Node)
+}

+ 36 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/delegate.go

@@ -0,0 +1,36 @@
+package memberlist
+
+// Delegate is the interface that clients must implement if they want to hook
+// into the gossip layer of Memberlist. All the methods must be thread-safe,
+// as they can and generally will be called concurrently.
+type Delegate interface {
+	// NodeMeta is used to retrieve meta-data about the current node
+	// when broadcasting an alive message. It's length is limited to
+	// the given byte size. This metadata is available in the Node structure.
+	NodeMeta(limit int) []byte
+
+	// NotifyMsg is called when a user-data message is received.
+	// Care should be taken that this method does not block, since doing
+	// so would block the entire UDP packet receive loop. Additionally, the byte
+	// slice may be modified after the call returns, so it should be copied if needed.
+	NotifyMsg([]byte)
+
+	// GetBroadcasts is called when user data messages can be broadcast.
+	// It can return a list of buffers to send. Each buffer should assume an
+	// overhead as provided with a limit on the total byte size allowed.
+	// The total byte size of the resulting data to send must not exceed
+	// the limit.
+	GetBroadcasts(overhead, limit int) [][]byte
+
+	// LocalState is used for a TCP Push/Pull. This is sent to
+	// the remote side in addition to the membership information. Any
+	// data can be sent here. See MergeRemoteState as well. The `join`
+	// boolean indicates this is for a join instead of a push/pull.
+	LocalState(join bool) []byte
+
+	// MergeRemoteState is invoked after a TCP Push/Pull. This is the
+	// state received from the remote side and is the result of the
+	// remote side's LocalState call. The 'join'
+	// boolean indicates this is for a join instead of a push/pull.
+	MergeRemoteState(buf []byte, join bool)
+}

+ 61 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/event_delegate.go

@@ -0,0 +1,61 @@
+package memberlist
+
+// EventDelegate is a simpler delegate that is used only to receive
+// notifications about members joining and leaving. The methods in this
+// delegate may be called by multiple goroutines, but never concurrently.
+// This allows you to reason about ordering.
+type EventDelegate interface {
+	// NotifyJoin is invoked when a node is detected to have joined.
+	// The Node argument must not be modified.
+	NotifyJoin(*Node)
+
+	// NotifyLeave is invoked when a node is detected to have left.
+	// The Node argument must not be modified.
+	NotifyLeave(*Node)
+
+	// NotifyUpdate is invoked when a node is detected to have
+	// updated, usually involving the meta data. The Node argument
+	// must not be modified.
+	NotifyUpdate(*Node)
+}
+
+// ChannelEventDelegate is used to enable an application to receive
+// events about joins and leaves over a channel instead of a direct
+// function call.
+//
+// Care must be taken that events are processed in a timely manner from
+// the channel, since this delegate will block until an event can be sent.
+type ChannelEventDelegate struct {
+	Ch chan<- NodeEvent
+}
+
+// NodeEventType are the types of events that can be sent from the
+// ChannelEventDelegate.
+type NodeEventType int
+
+const (
+	NodeJoin NodeEventType = iota
+	NodeLeave
+	NodeUpdate
+)
+
+// NodeEvent is a single event related to node activity in the memberlist.
+// The Node member of this struct must not be directly modified. It is passed
+// as a pointer to avoid unnecessary copies. If you wish to modify the node,
+// make a copy first.
+type NodeEvent struct {
+	Event NodeEventType
+	Node  *Node
+}
+
+func (c *ChannelEventDelegate) NotifyJoin(n *Node) {
+	c.Ch <- NodeEvent{NodeJoin, n}
+}
+
+func (c *ChannelEventDelegate) NotifyLeave(n *Node) {
+	c.Ch <- NodeEvent{NodeLeave, n}
+}
+
+func (c *ChannelEventDelegate) NotifyUpdate(n *Node) {
+	c.Ch <- NodeEvent{NodeUpdate, n}
+}

+ 89 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/integ_test.go

@@ -0,0 +1,89 @@
+package memberlist
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"testing"
+	"time"
+)
+
+// CheckInteg will skip a test if integration testing is not enabled.
+func CheckInteg(t *testing.T) {
+	if !IsInteg() {
+		t.SkipNow()
+	}
+}
+
+// IsInteg returns a boolean telling you if we're in integ testing mode.
+func IsInteg() bool {
+	return os.Getenv("INTEG_TESTS") != ""
+}
+
+// Tests the memberlist by creating a cluster of 100 nodes
+// and checking that we get strong convergence of changes.
+func TestMemberlist_Integ(t *testing.T) {
+	CheckInteg(t)
+
+	num := 16
+	var members []*Memberlist
+
+	secret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+	eventCh := make(chan NodeEvent, num)
+
+	addr := "127.0.0.1"
+	for i := 0; i < num; i++ {
+		c := DefaultLANConfig()
+		c.Name = fmt.Sprintf("%s:%d", addr, 12345+i)
+		c.BindAddr = addr
+		c.BindPort = 12345 + i
+		c.ProbeInterval = 20 * time.Millisecond
+		c.ProbeTimeout = 100 * time.Millisecond
+		c.GossipInterval = 20 * time.Millisecond
+		c.PushPullInterval = 200 * time.Millisecond
+		c.SecretKey = secret
+
+		if i == 0 {
+			c.Events = &ChannelEventDelegate{eventCh}
+		}
+
+		m, err := Create(c)
+		if err != nil {
+			t.Fatalf("unexpected err: %s", err)
+		}
+		members = append(members, m)
+		defer m.Shutdown()
+
+		if i > 0 {
+			last := members[i-1]
+			num, err := m.Join([]string{last.config.Name})
+			if num == 0 || err != nil {
+				t.Fatalf("unexpected err: %s", err)
+			}
+		}
+	}
+
+	// Wait and print debug info
+	breakTimer := time.After(250 * time.Millisecond)
+WAIT:
+	for {
+		select {
+		case e := <-eventCh:
+			if e.Event == NodeJoin {
+				log.Printf("[DEBUG] Node join: %v (%d)", *e.Node, members[0].NumMembers())
+			} else {
+				log.Printf("[DEBUG] Node leave: %v (%d)", *e.Node, members[0].NumMembers())
+			}
+		case <-breakTimer:
+			break WAIT
+		}
+	}
+
+	for idx, m := range members {
+		got := m.NumMembers()
+		if got != num {
+			t.Errorf("bad num members at idx %d. Expected %d. Got %d.",
+				idx, num, got)
+		}
+	}
+}

+ 144 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/keyring.go

@@ -0,0 +1,144 @@
+package memberlist
+
+import (
+	"bytes"
+	"fmt"
+	"sync"
+)
+
+type Keyring struct {
+	// Keys stores the key data used during encryption and decryption. It is
+	// ordered in such a way where the first key (index 0) is the primary key,
+	// which is used for encrypting messages, and is the first key tried during
+	// message decryption.
+	keys [][]byte
+
+	// The keyring lock is used while performing IO operations on the keyring.
+	l sync.Mutex
+}
+
+// Init allocates substructures
+func (k *Keyring) init() {
+	k.keys = make([][]byte, 0)
+}
+
+// NewKeyring constructs a new container for a set of encryption keys. The
+// keyring contains all key data used internally by memberlist.
+//
+// While creating a new keyring, you must do one of:
+//   - Omit keys and primary key, effectively disabling encryption
+//   - Pass a set of keys plus the primary key
+//   - Pass only a primary key
+//
+// If only a primary key is passed, then it will be automatically added to the
+// keyring. If creating a keyring with multiple keys, one key must be designated
+// primary by passing it as the primaryKey. If the primaryKey does not exist in
+// the list of secondary keys, it will be automatically added at position 0.
+func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
+	keyring := &Keyring{}
+	keyring.init()
+
+	if len(keys) > 0 || len(primaryKey) > 0 {
+		if len(primaryKey) == 0 {
+			return nil, fmt.Errorf("Empty primary key not allowed")
+		}
+		if err := keyring.AddKey(primaryKey); err != nil {
+			return nil, err
+		}
+		for _, key := range keys {
+			if err := keyring.AddKey(key); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return keyring, nil
+}
+
+// AddKey will install a new key on the ring. Adding a key to the ring will make
+// it available for use in decryption. If the key already exists on the ring,
+// this function will just return noop.
+func (k *Keyring) AddKey(key []byte) error {
+	// Encorce 16-byte key size
+	if len(key) != 16 {
+		return fmt.Errorf("key size must be 16 bytes")
+	}
+
+	// No-op if key is already installed
+	for _, installedKey := range k.keys {
+		if bytes.Equal(installedKey, key) {
+			return nil
+		}
+	}
+
+	keys := append(k.keys, key)
+	primaryKey := k.GetPrimaryKey()
+	if primaryKey == nil {
+		primaryKey = key
+	}
+	k.installKeys(keys, primaryKey)
+	return nil
+}
+
+// UseKey changes the key used to encrypt messages. This is the only key used to
+// encrypt messages, so peers should know this key before this method is called.
+func (k *Keyring) UseKey(key []byte) error {
+	for _, installedKey := range k.keys {
+		if bytes.Equal(key, installedKey) {
+			k.installKeys(k.keys, key)
+			return nil
+		}
+	}
+	return fmt.Errorf("Requested key is not in the keyring")
+}
+
+// RemoveKey drops a key from the keyring. This will return an error if the key
+// requested for removal is currently at position 0 (primary key).
+func (k *Keyring) RemoveKey(key []byte) error {
+	if bytes.Equal(key, k.keys[0]) {
+		return fmt.Errorf("Removing the primary key is not allowed")
+	}
+	for i, installedKey := range k.keys {
+		if bytes.Equal(key, installedKey) {
+			keys := append(k.keys[:i], k.keys[i+1:]...)
+			k.installKeys(keys, k.keys[0])
+		}
+	}
+	return nil
+}
+
+// installKeys will take out a lock on the keyring, and replace the keys with a
+// new set of keys. The key indicated by primaryKey will be installed as the new
+// primary key.
+func (k *Keyring) installKeys(keys [][]byte, primaryKey []byte) {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	newKeys := [][]byte{primaryKey}
+	for _, key := range keys {
+		if !bytes.Equal(key, primaryKey) {
+			newKeys = append(newKeys, key)
+		}
+	}
+	k.keys = newKeys
+}
+
+// GetKeys returns the current set of keys on the ring.
+func (k *Keyring) GetKeys() [][]byte {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	return k.keys
+}
+
+// GetPrimaryKey returns the key on the ring at position 0. This is the key used
+// for encrypting messages, and is the first key tried for decrypting messages.
+func (k *Keyring) GetPrimaryKey() (key []byte) {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	if len(k.keys) > 0 {
+		key = k.keys[0]
+	}
+	return
+}

+ 154 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/keyring_test.go

@@ -0,0 +1,154 @@
+package memberlist
+
+import (
+	"bytes"
+	"testing"
+)
+
+var TestKeys [][]byte = [][]byte{
+	[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+	[]byte{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+	[]byte{8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7},
+}
+
+func TestKeyring_EmptyRing(t *testing.T) {
+	// Keyrings can be created with no encryption keys (disabled encryption)
+	keyring, err := NewKeyring(nil, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	keys := keyring.GetKeys()
+	if len(keys) != 0 {
+		t.Fatalf("Expected 0 keys but have %d", len(keys))
+	}
+}
+
+func TestKeyring_PrimaryOnly(t *testing.T) {
+	// Keyrings can be created using only a primary key
+	keyring, err := NewKeyring(nil, TestKeys[0])
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	keys := keyring.GetKeys()
+	if len(keys) != 1 {
+		t.Fatalf("Expected 1 key but have %d", len(keys))
+	}
+}
+
+func TestKeyring_GetPrimaryKey(t *testing.T) {
+	keyring, err := NewKeyring(TestKeys, TestKeys[1])
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// GetPrimaryKey returns correct key
+	primaryKey := keyring.GetPrimaryKey()
+	if !bytes.Equal(primaryKey, TestKeys[1]) {
+		t.Fatalf("Unexpected primary key: %v", primaryKey)
+	}
+}
+
+func TestKeyring_AddRemoveUse(t *testing.T) {
+	keyring, err := NewKeyring(nil, TestKeys[1])
+	if err != nil {
+		t.Fatalf("err :%s", err)
+	}
+
+	// Use non-existent key throws error
+	if err := keyring.UseKey(TestKeys[2]); err == nil {
+		t.Fatalf("Expected key not installed error")
+	}
+
+	// Add key to ring
+	if err := keyring.AddKey(TestKeys[2]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	keys := keyring.GetKeys()
+	if !bytes.Equal(keys[0], TestKeys[1]) {
+		t.Fatalf("Unexpected primary key change")
+	}
+
+	if len(keys) != 2 {
+		t.Fatalf("Expected 2 keys but have %d", len(keys))
+	}
+
+	// Use key that exists should succeed
+	if err := keyring.UseKey(TestKeys[2]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	primaryKey := keyring.GetPrimaryKey()
+	if !bytes.Equal(primaryKey, TestKeys[2]) {
+		t.Fatalf("Unexpected primary key: %v", primaryKey)
+	}
+
+	// Removing primary key should fail
+	if err := keyring.RemoveKey(TestKeys[2]); err == nil {
+		t.Fatalf("Expected primary key removal error")
+	}
+
+	// Removing non-primary key should succeed
+	if err := keyring.RemoveKey(TestKeys[1]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	keys = keyring.GetKeys()
+	if len(keys) != 1 {
+		t.Fatalf("Expected 1 key but have %d", len(keys))
+	}
+}
+
+func TestKeyRing_MultiKeyEncryptDecrypt(t *testing.T) {
+	plaintext := []byte("this is a plain text message")
+	extra := []byte("random data")
+
+	keyring, err := NewKeyring(TestKeys, TestKeys[0])
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// First encrypt using the primary key and make sure we can decrypt
+	var buf bytes.Buffer
+	err = encryptPayload(1, TestKeys[0], plaintext, extra, &buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	msg, err := decryptPayload(keyring.GetKeys(), buf.Bytes(), extra)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if !bytes.Equal(msg, plaintext) {
+		t.Fatalf("bad: %v", msg)
+	}
+
+	// Now encrypt with a secondary key and try decrypting again.
+	buf.Reset()
+	err = encryptPayload(1, TestKeys[2], plaintext, extra, &buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	msg, err = decryptPayload(keyring.GetKeys(), buf.Bytes(), extra)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if !bytes.Equal(msg, plaintext) {
+		t.Fatalf("bad: %v", msg)
+	}
+
+	// Remove a key from the ring, and then try decrypting again
+	if err := keyring.RemoveKey(TestKeys[2]); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	msg, err = decryptPayload(keyring.GetKeys(), buf.Bytes(), extra)
+	if err == nil {
+		t.Fatalf("Expected no keys to decrypt message")
+	}
+}

+ 525 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/memberlist.go

@@ -0,0 +1,525 @@
+/*
+memberlist is a library that manages cluster
+membership and member failure detection using a gossip based protocol.
+
+The use cases for such a library are far-reaching: all distributed systems
+require membership, and memberlist is a re-usable solution to managing
+cluster membership and node failure detection.
+
+memberlist is eventually consistent but converges quickly on average.
+The speed at which it converges can be heavily tuned via various knobs
+on the protocol. Node failures are detected and network partitions are partially
+tolerated by attempting to communicate to potentially dead nodes through
+multiple routes.
+*/
+package memberlist
+
+import (
+	"fmt"
+	"log"
+	"net"
+	"os"
+	"strconv"
+	"sync"
+	"time"
+)
+
+type Memberlist struct {
+	config         *Config
+	shutdown       bool
+	shutdownCh     chan struct{}
+	leave          bool
+	leaveBroadcast chan struct{}
+
+	udpListener *net.UDPConn
+	tcpListener *net.TCPListener
+	handoff     chan msgHandoff
+
+	sequenceNum uint32 // Local sequence number
+	incarnation uint32 // Local incarnation number
+
+	nodeLock sync.RWMutex
+	nodes    []*nodeState          // Known nodes
+	nodeMap  map[string]*nodeState // Maps Addr.String() -> NodeState
+
+	tickerLock sync.Mutex
+	tickers    []*time.Ticker
+	stopTick   chan struct{}
+	probeIndex int
+
+	ackLock     sync.Mutex
+	ackHandlers map[uint32]*ackHandler
+
+	broadcasts *TransmitLimitedQueue
+
+	startStopLock sync.Mutex
+
+	logger *log.Logger
+}
+
+// newMemberlist creates the network listeners.
+// Does not schedule execution of background maintenence.
+func newMemberlist(conf *Config) (*Memberlist, error) {
+	if conf.ProtocolVersion < ProtocolVersionMin {
+		return nil, fmt.Errorf("Protocol version '%d' too low. Must be in range: [%d, %d]",
+			conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+	} else if conf.ProtocolVersion > ProtocolVersionMax {
+		return nil, fmt.Errorf("Protocol version '%d' too high. Must be in range: [%d, %d]",
+			conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+	}
+
+	if len(conf.SecretKey) > 0 {
+		if conf.Keyring == nil {
+			keyring, err := NewKeyring(nil, conf.SecretKey)
+			if err != nil {
+				return nil, err
+			}
+			conf.Keyring = keyring
+		} else {
+			if err := conf.Keyring.AddKey(conf.SecretKey); err != nil {
+				return nil, err
+			}
+			if err := conf.Keyring.UseKey(conf.SecretKey); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	tcpAddr := &net.TCPAddr{IP: net.ParseIP(conf.BindAddr), Port: conf.BindPort}
+	tcpLn, err := net.ListenTCP("tcp", tcpAddr)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to start TCP listener. Err: %s", err)
+	}
+
+	udpAddr := &net.UDPAddr{IP: net.ParseIP(conf.BindAddr), Port: conf.BindPort}
+	udpLn, err := net.ListenUDP("udp", udpAddr)
+	if err != nil {
+		tcpLn.Close()
+		return nil, fmt.Errorf("Failed to start UDP listener. Err: %s", err)
+	}
+
+	// Set the UDP receive window size
+	setUDPRecvBuf(udpLn)
+
+	if conf.LogOutput == nil {
+		conf.LogOutput = os.Stderr
+	}
+	logger := log.New(conf.LogOutput, "", log.LstdFlags)
+
+	m := &Memberlist{
+		config:         conf,
+		shutdownCh:     make(chan struct{}),
+		leaveBroadcast: make(chan struct{}, 1),
+		udpListener:    udpLn,
+		tcpListener:    tcpLn,
+		handoff:        make(chan msgHandoff, 1024),
+		nodeMap:        make(map[string]*nodeState),
+		ackHandlers:    make(map[uint32]*ackHandler),
+		broadcasts:     &TransmitLimitedQueue{RetransmitMult: conf.RetransmitMult},
+		logger:         logger,
+	}
+	m.broadcasts.NumNodes = func() int { return len(m.nodes) }
+	go m.tcpListen()
+	go m.udpListen()
+	go m.udpHandler()
+	return m, nil
+}
+
+// Create will create a new Memberlist using the given configuration.
+// This will not connect to any other node (see Join) yet, but will start
+// all the listeners to allow other nodes to join this memberlist.
+// After creating a Memberlist, the configuration given should not be
+// modified by the user anymore.
+func Create(conf *Config) (*Memberlist, error) {
+	m, err := newMemberlist(conf)
+	if err != nil {
+		return nil, err
+	}
+	if err := m.setAlive(); err != nil {
+		m.Shutdown()
+		return nil, err
+	}
+	m.schedule()
+	return m, nil
+}
+
+// Join is used to take an existing Memberlist and attempt to join a cluster
+// by contacting all the given hosts and performing a state sync. Initially,
+// the Memberlist only contains our own state, so doing this will cause
+// remote nodes to become aware of the existence of this node, effectively
+// joining the cluster.
+//
+// This returns the number of hosts successfully contacted and an error if
+// none could be reached. If an error is returned, the node did not successfully
+// join the cluster.
+func (m *Memberlist) Join(existing []string) (int, error) {
+	// Attempt to join any of them
+	numSuccess := 0
+	var retErr error
+	for _, exist := range existing {
+		addrs, port, err := m.resolveAddr(exist)
+		if err != nil {
+			m.logger.Printf("[WARN] memberlist: Failed to resolve %s: %v", exist, err)
+			retErr = err
+			continue
+		}
+
+		for _, addr := range addrs {
+			if err := m.pushPullNode(addr, port, true); err != nil {
+				retErr = err
+				continue
+			}
+			numSuccess++
+		}
+
+	}
+
+	if numSuccess > 0 {
+		retErr = nil
+	}
+
+	return numSuccess, retErr
+}
+
+// resolveAddr is used to resolve the address into an address,
+// port, and error. If no port is given, use the default
+func (m *Memberlist) resolveAddr(hostStr string) ([][]byte, uint16, error) {
+	ips := make([][]byte, 0)
+	port := uint16(0)
+	host, sport, err := net.SplitHostPort(hostStr)
+	if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
+		// error, port missing - we can solve this
+		port = uint16(m.config.BindPort)
+		host = hostStr
+	} else if err != nil {
+		// error, but not missing port
+		return ips, port, err
+	} else if lport, err := strconv.ParseUint(sport, 10, 16); err != nil {
+		// error, when parsing port
+		return ips, port, err
+	} else {
+		// no error
+		port = uint16(lport)
+	}
+
+	// Get the addresses that hostPort might resolve to
+	// ResolveTcpAddr requres ipv6 brackets to separate
+	// port numbers whereas ParseIP doesn't, but luckily
+	// SplitHostPort takes care of the brackets
+	if ip := net.ParseIP(host); ip == nil {
+		if pre, err := net.LookupIP(host); err == nil {
+			for _, ip := range pre {
+				ips = append(ips, ip)
+			}
+		} else {
+			return ips, port, err
+		}
+	} else {
+		ips = append(ips, ip)
+	}
+
+	return ips, port, nil
+}
+
+// setAlive is used to mark this node as being alive. This is the same
+// as if we received an alive notification our own network channel for
+// ourself.
+func (m *Memberlist) setAlive() error {
+
+	var advertiseAddr []byte
+	var advertisePort int
+	if m.config.AdvertiseAddr != "" {
+		// If AdvertiseAddr is not empty, then advertise
+		// the given address and port.
+		ip := net.ParseIP(m.config.AdvertiseAddr)
+		if ip == nil {
+			return fmt.Errorf("Failed to parse advertise address!")
+		}
+
+		// Ensure IPv4 conversion if necessary
+		if ip4 := ip.To4(); ip4 != nil {
+			ip = ip4
+		}
+
+		advertiseAddr = ip
+		advertisePort = m.config.AdvertisePort
+	} else {
+		if m.config.BindAddr == "0.0.0.0" {
+			// Otherwise, if we're not bound to a specific IP,
+			//let's list the interfaces on this machine and use
+			// the first private IP we find.
+			addresses, err := net.InterfaceAddrs()
+			if err != nil {
+				return fmt.Errorf("Failed to get interface addresses! Err: %v", err)
+			}
+
+			// Find private IPv4 address
+			for _, rawAddr := range addresses {
+				var ip net.IP
+				switch addr := rawAddr.(type) {
+				case *net.IPAddr:
+					ip = addr.IP
+				case *net.IPNet:
+					ip = addr.IP
+				default:
+					continue
+				}
+
+				if ip.To4() == nil {
+					continue
+				}
+				if !isPrivateIP(ip.String()) {
+					continue
+				}
+
+				advertiseAddr = ip
+				break
+			}
+
+			// Failed to find private IP, error
+			if advertiseAddr == nil {
+				return fmt.Errorf("No private IP address found, and explicit IP not provided")
+			}
+
+		} else {
+			// Use the IP that we're bound to.
+			addr := m.tcpListener.Addr().(*net.TCPAddr)
+			advertiseAddr = addr.IP
+		}
+		advertisePort = m.config.BindPort
+	}
+
+	// Check if this is a public address without encryption
+	addrStr := net.IP(advertiseAddr).String()
+	if !isPrivateIP(addrStr) && !isLoopbackIP(addrStr) && !m.config.EncryptionEnabled() {
+		m.logger.Printf("[WARN] memberlist: Binding to public address without encryption!")
+	}
+
+	// Get the node meta data
+	var meta []byte
+	if m.config.Delegate != nil {
+		meta = m.config.Delegate.NodeMeta(MetaMaxSize)
+		if len(meta) > MetaMaxSize {
+			panic("Node meta data provided is longer than the limit")
+		}
+	}
+
+	a := alive{
+		Incarnation: m.nextIncarnation(),
+		Node:        m.config.Name,
+		Addr:        advertiseAddr,
+		Port:        uint16(advertisePort),
+		Meta:        meta,
+		Vsn: []uint8{
+			ProtocolVersionMin, ProtocolVersionMax, m.config.ProtocolVersion,
+			m.config.DelegateProtocolMin, m.config.DelegateProtocolMax,
+			m.config.DelegateProtocolVersion,
+		},
+	}
+	m.aliveNode(&a, nil, true)
+
+	return nil
+}
+
+// LocalNode is used to return the local Node
+func (m *Memberlist) LocalNode() *Node {
+	m.nodeLock.RLock()
+	defer m.nodeLock.RUnlock()
+	state := m.nodeMap[m.config.Name]
+	return &state.Node
+}
+
+// UpdateNode is used to trigger re-advertising the local node. This is
+// primarily used with a Delegate to support dynamic updates to the local
+// meta data.  This will block until the update message is successfully
+// broadcasted to a member of the cluster, if any exist or until a specified
+// timeout is reached.
+func (m *Memberlist) UpdateNode(timeout time.Duration) error {
+	// Get the node meta data
+	var meta []byte
+	if m.config.Delegate != nil {
+		meta = m.config.Delegate.NodeMeta(MetaMaxSize)
+		if len(meta) > MetaMaxSize {
+			panic("Node meta data provided is longer than the limit")
+		}
+	}
+
+	// Get the existing node
+	m.nodeLock.RLock()
+	state := m.nodeMap[m.config.Name]
+	m.nodeLock.RUnlock()
+
+	// Format a new alive message
+	a := alive{
+		Incarnation: m.nextIncarnation(),
+		Node:        m.config.Name,
+		Addr:        state.Addr,
+		Port:        state.Port,
+		Meta:        meta,
+		Vsn: []uint8{
+			ProtocolVersionMin, ProtocolVersionMax, m.config.ProtocolVersion,
+			m.config.DelegateProtocolMin, m.config.DelegateProtocolMax,
+			m.config.DelegateProtocolVersion,
+		},
+	}
+	notifyCh := make(chan struct{})
+	m.aliveNode(&a, notifyCh, true)
+
+	// Wait for the broadcast or a timeout
+	if m.anyAlive() {
+		var timeoutCh <-chan time.Time
+		if timeout > 0 {
+			timeoutCh = time.After(timeout)
+		}
+		select {
+		case <-notifyCh:
+		case <-timeoutCh:
+			return fmt.Errorf("timeout waiting for update broadcast")
+		}
+	}
+	return nil
+}
+
+// SendTo is used to directly send a message to another node, without
+// the use of the gossip mechanism. This will encode the message as a
+// user-data message, which a delegate will receive through NotifyMsg
+// The actual data is transmitted over UDP, which means this is a
+// best-effort transmission mechanism, and the maximum size of the
+// message is the size of a single UDP datagram, after compression
+func (m *Memberlist) SendTo(to net.Addr, msg []byte) error {
+	// Encode as a user message
+	buf := make([]byte, 1, len(msg)+1)
+	buf[0] = byte(userMsg)
+	buf = append(buf, msg...)
+
+	// Send the message
+	return m.rawSendMsg(to, buf)
+}
+
+// Members returns a list of all known live nodes. The node structures
+// returned must not be modified. If you wish to modify a Node, make a
+// copy first.
+func (m *Memberlist) Members() []*Node {
+	m.nodeLock.RLock()
+	defer m.nodeLock.RUnlock()
+
+	nodes := make([]*Node, 0, len(m.nodes))
+	for _, n := range m.nodes {
+		if n.State != stateDead {
+			nodes = append(nodes, &n.Node)
+		}
+	}
+
+	return nodes
+}
+
+// NumMembers returns the number of alive nodes currently known. Between
+// the time of calling this and calling Members, the number of alive nodes
+// may have changed, so this shouldn't be used to determine how many
+// members will be returned by Members.
+func (m *Memberlist) NumMembers() (alive int) {
+	m.nodeLock.RLock()
+	defer m.nodeLock.RUnlock()
+
+	for _, n := range m.nodes {
+		if n.State != stateDead {
+			alive++
+		}
+	}
+
+	return
+}
+
+// Leave will broadcast a leave message but will not shutdown the background
+// listeners, meaning the node will continue participating in gossip and state
+// updates.
+//
+// This will block until the leave message is successfully broadcasted to
+// a member of the cluster, if any exist or until a specified timeout
+// is reached.
+//
+// This method is safe to call multiple times, but must not be called
+// after the cluster is already shut down.
+func (m *Memberlist) Leave(timeout time.Duration) error {
+	m.startStopLock.Lock()
+	defer m.startStopLock.Unlock()
+
+	if m.shutdown {
+		panic("leave after shutdown")
+	}
+
+	if !m.leave {
+		m.leave = true
+
+		state, ok := m.nodeMap[m.config.Name]
+		if !ok {
+			m.logger.Printf("[WARN] memberlist: Leave but we're not in the node map.")
+			return nil
+		}
+
+		d := dead{
+			Incarnation: state.Incarnation,
+			Node:        state.Name,
+		}
+		m.deadNode(&d)
+
+		// Block until the broadcast goes out
+		if m.anyAlive() {
+			var timeoutCh <-chan time.Time
+			if timeout > 0 {
+				timeoutCh = time.After(timeout)
+			}
+			select {
+			case <-m.leaveBroadcast:
+			case <-timeoutCh:
+				return fmt.Errorf("timeout waiting for leave broadcast")
+			}
+		}
+	}
+
+	return nil
+}
+
+// Check for any other alive node.
+func (m *Memberlist) anyAlive() bool {
+	m.nodeLock.RLock()
+	defer m.nodeLock.RUnlock()
+	for _, n := range m.nodes {
+		if n.State != stateDead && n.Name != m.config.Name {
+			return true
+		}
+	}
+	return false
+}
+
+// ProtocolVersion returns the protocol version currently in use by
+// this memberlist.
+func (m *Memberlist) ProtocolVersion() uint8 {
+	// NOTE: This method exists so that in the future we can control
+	// any locking if necessary, if we change the protocol version at
+	// runtime, etc.
+	return m.config.ProtocolVersion
+}
+
+// Shutdown will stop any background maintanence of network activity
+// for this memberlist, causing it to appear "dead". A leave message
+// will not be broadcasted prior, so the cluster being left will have
+// to detect this node's shutdown using probing. If you wish to more
+// gracefully exit the cluster, call Leave prior to shutting down.
+//
+// This method is safe to call multiple times.
+func (m *Memberlist) Shutdown() error {
+	m.startStopLock.Lock()
+	defer m.startStopLock.Unlock()
+
+	if m.shutdown {
+		return nil
+	}
+
+	m.shutdown = true
+	close(m.shutdownCh)
+	m.deschedule()
+	m.udpListener.Close()
+	m.tcpListener.Close()
+	return nil
+}

+ 1144 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/memberlist_test.go

@@ -0,0 +1,1144 @@
+package memberlist
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"net"
+	"reflect"
+	"sync"
+	"testing"
+	"time"
+)
+
+var bindLock sync.Mutex
+var bindNum byte = 10
+
+func getBindAddr() net.IP {
+	bindLock.Lock()
+	defer bindLock.Unlock()
+
+	result := net.IPv4(127, 0, 0, bindNum)
+	bindNum++
+	if bindNum > 255 {
+		bindNum = 10
+	}
+
+	return result
+}
+
+func testConfig() *Config {
+	config := DefaultLANConfig()
+	config.BindAddr = getBindAddr().String()
+	config.Name = config.BindAddr
+	return config
+}
+
+func yield() {
+	time.Sleep(5 * time.Millisecond)
+}
+
+type MockDelegate struct {
+	meta        []byte
+	msgs        [][]byte
+	broadcasts  [][]byte
+	state       []byte
+	remoteState []byte
+}
+
+func (m *MockDelegate) NodeMeta(limit int) []byte {
+	return m.meta
+}
+
+func (m *MockDelegate) NotifyMsg(msg []byte) {
+	cp := make([]byte, len(msg))
+	copy(cp, msg)
+	m.msgs = append(m.msgs, cp)
+}
+
+func (m *MockDelegate) GetBroadcasts(overhead, limit int) [][]byte {
+	b := m.broadcasts
+	m.broadcasts = nil
+	return b
+}
+
+func (m *MockDelegate) LocalState(join bool) []byte {
+	return m.state
+}
+
+func (m *MockDelegate) MergeRemoteState(s []byte, join bool) {
+	m.remoteState = s
+}
+
+func GetMemberlistDelegate(t *testing.T) (*Memberlist, *MockDelegate) {
+	d := &MockDelegate{}
+
+	c := testConfig()
+	c.Delegate = d
+
+	var m *Memberlist
+	var err error
+	for i := 0; i < 100; i++ {
+		m, err = newMemberlist(c)
+		if err == nil {
+			return m, d
+		}
+		c.BindPort++
+	}
+	t.Fatalf("failed to start: %v", err)
+	return nil, nil
+}
+
+func GetMemberlist(t *testing.T) *Memberlist {
+	c := testConfig()
+
+	var m *Memberlist
+	var err error
+	for i := 0; i < 100; i++ {
+		m, err = newMemberlist(c)
+		if err == nil {
+			return m
+		}
+		c.BindPort++
+	}
+	t.Fatalf("failed to start: %v", err)
+	return nil
+}
+
+func TestDefaultLANConfig_protocolVersion(t *testing.T) {
+	c := DefaultLANConfig()
+	if c.ProtocolVersion != ProtocolVersionMax {
+		t.Fatalf("should be max: %d", c.ProtocolVersion)
+	}
+}
+
+func TestCreate_protocolVersion(t *testing.T) {
+	cases := []struct {
+		version uint8
+		err     bool
+	}{
+		{ProtocolVersionMin, false},
+		{ProtocolVersionMax, false},
+		// TODO(mitchellh): uncommon when we're over 0
+		//{ProtocolVersionMin - 1, true},
+		{ProtocolVersionMax + 1, true},
+		{ProtocolVersionMax - 1, false},
+	}
+
+	for _, tc := range cases {
+		c := DefaultLANConfig()
+		c.BindAddr = getBindAddr().String()
+		c.ProtocolVersion = tc.version
+		m, err := Create(c)
+		if tc.err && err == nil {
+			t.Errorf("Should've failed with version: %d", tc.version)
+		} else if !tc.err && err != nil {
+			t.Errorf("Version '%d' error: %s", tc.version, err)
+		}
+
+		if err == nil {
+			m.Shutdown()
+		}
+	}
+}
+
+func TestCreate_secretKey(t *testing.T) {
+	cases := []struct {
+		key []byte
+		err bool
+	}{
+		{make([]byte, 0), false},
+		{[]byte("abc"), true},
+		{make([]byte, 16), false},
+		{make([]byte, 32), true},
+	}
+
+	for _, tc := range cases {
+		c := DefaultLANConfig()
+		c.BindAddr = getBindAddr().String()
+		c.SecretKey = tc.key
+		m, err := Create(c)
+		if tc.err && err == nil {
+			t.Errorf("Should've failed with key: %#v", tc.key)
+		} else if !tc.err && err != nil {
+			t.Errorf("Key '%#v' error: %s", tc.key, err)
+		}
+
+		if err == nil {
+			m.Shutdown()
+		}
+	}
+}
+
+func TestCreate_secretKeyEmpty(t *testing.T) {
+	c := DefaultLANConfig()
+	c.BindAddr = getBindAddr().String()
+	c.SecretKey = make([]byte, 0)
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	if m.config.EncryptionEnabled() {
+		t.Fatalf("Expected encryption to be disabled")
+	}
+}
+
+func TestCreate_keyringOnly(t *testing.T) {
+	c := DefaultLANConfig()
+	c.BindAddr = getBindAddr().String()
+	keyring, err := NewKeyring(nil, make([]byte, 16))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	c.Keyring = keyring
+
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	if !m.config.EncryptionEnabled() {
+		t.Fatalf("Expected encryption to be enabled")
+	}
+}
+
+func TestCreate_keyringAndSecretKey(t *testing.T) {
+	c := DefaultLANConfig()
+	c.BindAddr = getBindAddr().String()
+	keyring, err := NewKeyring(nil, make([]byte, 16))
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	c.Keyring = keyring
+	c.SecretKey = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	if !m.config.EncryptionEnabled() {
+		t.Fatalf("Expected encryption to be enabled")
+	}
+
+	ringKeys := c.Keyring.GetKeys()
+	if !bytes.Equal(c.SecretKey, ringKeys[0]) {
+		t.Fatalf("Unexpected primary key %v", ringKeys[0])
+	}
+}
+
+func TestCreate(t *testing.T) {
+	c := testConfig()
+	c.ProtocolVersion = ProtocolVersionMin
+	c.DelegateProtocolVersion = 13
+	c.DelegateProtocolMin = 12
+	c.DelegateProtocolMax = 24
+
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	yield()
+
+	members := m.Members()
+	if len(members) != 1 {
+		t.Fatalf("bad number of members")
+	}
+
+	if members[0].PMin != ProtocolVersionMin {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].PMax != ProtocolVersionMax {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].PCur != c.ProtocolVersion {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].DMin != c.DelegateProtocolMin {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].DMax != c.DelegateProtocolMax {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].DCur != c.DelegateProtocolVersion {
+		t.Fatalf("bad: %#v", members[0])
+	}
+}
+
+func TestMemberList_CreateShutdown(t *testing.T) {
+	m := GetMemberlist(t)
+	m.schedule()
+	if err := m.Shutdown(); err != nil {
+		t.Fatalf("failed to shutdown %v", err)
+	}
+}
+
+func TestMemberList_ResolveAddr(t *testing.T) {
+	m := GetMemberlist(t)
+	if _, _, err := m.resolveAddr("localhost"); err != nil {
+		t.Fatalf("Could not resolve localhost: %s", err)
+	}
+	if _, _, err := m.resolveAddr("[::1]:80"); err != nil {
+		t.Fatalf("Could not understand ipv6 pair: %s", err)
+	}
+	if _, _, err := m.resolveAddr("[::1]"); err == nil {
+		t.Fatalf("Understood bracketed non-pair")
+	}
+	if _, _, err := m.resolveAddr(":80"); err == nil {
+		t.Fatalf("Understood hostless port")
+	}
+	if _, _, err := m.resolveAddr("localhost:80"); err != nil {
+		t.Fatalf("Could not understand hostname port combo: %s", err)
+	}
+	if _, _, err := m.resolveAddr("localhost:80000"); err == nil {
+		t.Fatalf("Understood too high port")
+	}
+}
+
+func TestMemberList_Members(t *testing.T) {
+	n1 := &Node{Name: "test"}
+	n2 := &Node{Name: "test2"}
+	n3 := &Node{Name: "test3"}
+
+	m := &Memberlist{}
+	nodes := []*nodeState{
+		&nodeState{Node: *n1, State: stateAlive},
+		&nodeState{Node: *n2, State: stateDead},
+		&nodeState{Node: *n3, State: stateSuspect},
+	}
+	m.nodes = nodes
+
+	members := m.Members()
+	if !reflect.DeepEqual(members, []*Node{n1, n3}) {
+		t.Fatalf("bad members")
+	}
+}
+
+func TestMemberlist_Join(t *testing.T) {
+	m1 := GetMemberlist(t)
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+}
+
+type CustomMergeDelegate struct {
+	invoked bool
+}
+
+func (c *CustomMergeDelegate) NotifyMerge(nodes []*Node) (cancel bool) {
+	log.Printf("Cancel merge")
+	c.invoked = true
+	return true
+}
+
+func TestMemberlist_Join_Cancel(t *testing.T) {
+	m1 := GetMemberlist(t)
+	merge1 := &CustomMergeDelegate{}
+	m1.config.Merge = merge1
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatal("unexpected err: %s", err)
+	}
+	merge2 := &CustomMergeDelegate{}
+	m2.config.Merge = merge2
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 0 {
+		t.Fatalf("unexpected 0: %d", num)
+	}
+	if err.Error() != "Merge canceled" {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 1 {
+		t.Fatalf("should have 1 nodes! %v", m2.Members())
+	}
+	if len(m1.Members()) != 1 {
+		t.Fatalf("should have 1 nodes! %v", m1.Members())
+	}
+
+	// Check delegate invocation
+	if !merge1.invoked {
+		t.Fatalf("should invoke delegate")
+	}
+	if !merge2.invoked {
+		t.Fatalf("should invoke delegate")
+	}
+}
+
+func TestMemberlist_Join_protocolVersions(t *testing.T) {
+	c1 := testConfig()
+	c2 := testConfig()
+	c3 := testConfig()
+	c3.ProtocolVersion = ProtocolVersionMax
+
+	m1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m1.Shutdown()
+
+	m2, err := Create(c2)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	m3, err := Create(c3)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m3.Shutdown()
+
+	_, err = m1.Join([]string{c2.BindAddr})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	yield()
+
+	_, err = m1.Join([]string{c3.BindAddr})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestMemberlist_Leave(t *testing.T) {
+	m1 := GetMemberlist(t)
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+	c.GossipInterval = time.Millisecond
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+	if len(m1.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	// Leave
+	m1.Leave(time.Second)
+
+	// Wait for leave
+	time.Sleep(10 * time.Millisecond)
+
+	// m1 should think dead
+	if len(m1.Members()) != 1 {
+		t.Fatalf("should have 1 node")
+	}
+
+	if len(m2.Members()) != 1 {
+		t.Fatalf("should have 1 node")
+	}
+}
+
+func TestMemberlist_JoinShutdown(t *testing.T) {
+	m1 := GetMemberlist(t)
+	m1.setAlive()
+	m1.schedule()
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+	c.ProbeInterval = time.Millisecond
+	c.ProbeTimeout = 100 * time.Microsecond
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	m1.Shutdown()
+
+	time.Sleep(10 * time.Millisecond)
+
+	if len(m2.Members()) != 1 {
+		t.Fatalf("should have 1 nodes! %v", m2.Members())
+	}
+}
+
+func TestMemberlist_delegateMeta(t *testing.T) {
+	c1 := testConfig()
+	c2 := testConfig()
+	c1.Delegate = &MockDelegate{meta: []byte("web")}
+	c2.Delegate = &MockDelegate{meta: []byte("lb")}
+
+	m1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m1.Shutdown()
+
+	m2, err := Create(c2)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	_, err = m1.Join([]string{c2.BindAddr})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	yield()
+
+	var roles map[string]string
+
+	// Check the roles of members of m1
+	m1m := m1.Members()
+	if len(m1m) != 2 {
+		t.Fatalf("bad: %#v", m1m)
+	}
+
+	roles = make(map[string]string)
+	for _, m := range m1m {
+		roles[m.Name] = string(m.Meta)
+	}
+
+	if r := roles[c1.Name]; r != "web" {
+		t.Fatalf("bad role for %s: %s", c1.Name, r)
+	}
+
+	if r := roles[c2.Name]; r != "lb" {
+		t.Fatalf("bad role for %s: %s", c2.Name, r)
+	}
+
+	// Check the roles of members of m2
+	m2m := m2.Members()
+	if len(m2m) != 2 {
+		t.Fatalf("bad: %#v", m2m)
+	}
+
+	roles = make(map[string]string)
+	for _, m := range m2m {
+		roles[m.Name] = string(m.Meta)
+	}
+
+	if r := roles[c1.Name]; r != "web" {
+		t.Fatalf("bad role for %s: %s", c1.Name, r)
+	}
+
+	if r := roles[c2.Name]; r != "lb" {
+		t.Fatalf("bad role for %s: %s", c2.Name, r)
+	}
+}
+
+func TestMemberlist_delegateMeta_Update(t *testing.T) {
+	c1 := testConfig()
+	c2 := testConfig()
+	mock1 := &MockDelegate{meta: []byte("web")}
+	mock2 := &MockDelegate{meta: []byte("lb")}
+	c1.Delegate = mock1
+	c2.Delegate = mock2
+
+	m1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m1.Shutdown()
+
+	m2, err := Create(c2)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	_, err = m1.Join([]string{c2.BindAddr})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	yield()
+
+	// Update the meta data roles
+	mock1.meta = []byte("api")
+	mock2.meta = []byte("db")
+
+	m1.UpdateNode(0)
+	m2.UpdateNode(0)
+	yield()
+
+	// Check the updates have propagated
+	var roles map[string]string
+
+	// Check the roles of members of m1
+	m1m := m1.Members()
+	if len(m1m) != 2 {
+		t.Fatalf("bad: %#v", m1m)
+	}
+
+	roles = make(map[string]string)
+	for _, m := range m1m {
+		roles[m.Name] = string(m.Meta)
+	}
+
+	if r := roles[c1.Name]; r != "api" {
+		t.Fatalf("bad role for %s: %s", c1.Name, r)
+	}
+
+	if r := roles[c2.Name]; r != "db" {
+		t.Fatalf("bad role for %s: %s", c2.Name, r)
+	}
+
+	// Check the roles of members of m2
+	m2m := m2.Members()
+	if len(m2m) != 2 {
+		t.Fatalf("bad: %#v", m2m)
+	}
+
+	roles = make(map[string]string)
+	for _, m := range m2m {
+		roles[m.Name] = string(m.Meta)
+	}
+
+	if r := roles[c1.Name]; r != "api" {
+		t.Fatalf("bad role for %s: %s", c1.Name, r)
+	}
+
+	if r := roles[c2.Name]; r != "db" {
+		t.Fatalf("bad role for %s: %s", c2.Name, r)
+	}
+}
+
+func TestMemberlist_UserData(t *testing.T) {
+	m1, d1 := GetMemberlistDelegate(t)
+	d1.state = []byte("something")
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second delegate with things to send
+	d2 := &MockDelegate{}
+	d2.broadcasts = [][]byte{
+		[]byte("test"),
+		[]byte("foobar"),
+	}
+	d2.state = []byte("my state")
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+	c.GossipInterval = time.Millisecond
+	c.PushPullInterval = time.Millisecond
+	c.Delegate = d2
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	// Check the hosts
+	if m2.NumMembers() != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	// Wait for a little while
+	time.Sleep(3 * time.Millisecond)
+
+	// Ensure we got the messages
+	if len(d1.msgs) != 2 {
+		t.Fatalf("should have 2 messages!")
+	}
+	if !reflect.DeepEqual(d1.msgs[0], []byte("test")) {
+		t.Fatalf("bad msg %v", d1.msgs[0])
+	}
+	if !reflect.DeepEqual(d1.msgs[1], []byte("foobar")) {
+		t.Fatalf("bad msg %v", d1.msgs[1])
+	}
+
+	// Check the push/pull state
+	if !reflect.DeepEqual(d1.remoteState, []byte("my state")) {
+		t.Fatalf("bad state %s", d1.remoteState)
+	}
+	if !reflect.DeepEqual(d2.remoteState, []byte("something")) {
+		t.Fatalf("bad state %s", d2.remoteState)
+	}
+}
+
+func TestMemberlist_SendTo(t *testing.T) {
+	m1, d1 := GetMemberlistDelegate(t)
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second delegate with things to send
+	d2 := &MockDelegate{}
+
+	// Create a second node
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+	c.GossipInterval = time.Millisecond
+	c.PushPullInterval = time.Millisecond
+	c.Delegate = d2
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if m2.NumMembers() != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	// Try to do a direct send
+	m2Addr := &net.UDPAddr{IP: addr1,
+		Port: c.BindPort}
+	if err := m1.SendTo(m2Addr, []byte("ping")); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	m1Addr := &net.UDPAddr{IP: net.ParseIP(m1.config.BindAddr),
+		Port: m1.config.BindPort}
+	if err := m2.SendTo(m1Addr, []byte("pong")); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Wait for a little while
+	time.Sleep(3 * time.Millisecond)
+
+	// Ensure we got the messages
+	if len(d1.msgs) != 1 {
+		t.Fatalf("should have 1 messages!")
+	}
+	if !reflect.DeepEqual(d1.msgs[0], []byte("pong")) {
+		t.Fatalf("bad msg %v", d1.msgs[0])
+	}
+
+	if len(d2.msgs) != 1 {
+		t.Fatalf("should have 1 messages!")
+	}
+	if !reflect.DeepEqual(d2.msgs[0], []byte("ping")) {
+		t.Fatalf("bad msg %v", d2.msgs[0])
+	}
+}
+
+func TestMemberlistProtocolVersion(t *testing.T) {
+	c := DefaultLANConfig()
+	c.BindAddr = getBindAddr().String()
+	c.ProtocolVersion = ProtocolVersionMax
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	result := m.ProtocolVersion()
+	if result != ProtocolVersionMax {
+		t.Fatalf("bad: %d", result)
+	}
+}
+
+func TestMemberlist_Join_DeadNode(t *testing.T) {
+	m1 := GetMemberlist(t)
+	m1.config.TCPTimeout = 50 * time.Millisecond
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+
+	// Create a second "node", which is just a TCP listener that
+	// does not ever respond. This is to test our deadliens
+	addr1 := getBindAddr()
+	list, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr1.String(), m1.config.BindPort))
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer list.Close()
+
+	// Ensure we don't hang forever
+	timer := time.AfterFunc(100*time.Millisecond, func() {
+		panic("should have timed out by now")
+	})
+	defer timer.Stop()
+
+	num, err := m1.Join([]string{addr1.String()})
+	if num != 0 {
+		t.Fatalf("unexpected 0: %d", num)
+	}
+	if err == nil {
+		t.Fatal("expect err")
+	}
+}
+
+func TestMemberlist_Join_Proto1And2(t *testing.T) {
+	// Create first node, protocol 2
+	m1 := GetMemberlist(t)
+	m1.setAlive()
+	m1.schedule()
+	defer m1.Shutdown()
+	if m1.config.ProtocolVersion != 2 {
+		t.Fatalf("expected version 2")
+	}
+
+	// Create a second node, lower protocol!
+	c := DefaultLANConfig()
+	addr1 := getBindAddr()
+	c.Name = addr1.String()
+	c.BindAddr = addr1.String()
+	c.BindPort = m1.config.BindPort
+	c.ProtocolVersion = 1
+
+	m2, err := Create(c)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{m1.config.BindAddr})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	// Check the hosts
+	if len(m1.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+}
+
+func TestMemberlist_Join_IPv6(t *testing.T) {
+	c1 := DefaultLANConfig()
+	c1.Name = "A"
+	c1.BindAddr = "[::1]"
+	var m1 *Memberlist
+	var err error
+	for i := 0; i < 100; i++ {
+		c1.BindPort = 23456 + i
+		m1, err = Create(c1)
+		if err == nil {
+			break
+		}
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m1.Shutdown()
+
+	// Create a second node
+	c2 := DefaultLANConfig()
+	c2.Name = "B"
+	c2.BindAddr = "[::1]"
+	var m2 *Memberlist
+	for i := 0; i < 100; i++ {
+		c2.BindPort = c1.BindPort + 1 + i
+		m2, err = Create(c2)
+		if err == nil {
+			break
+		}
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	num, err := m2.Join([]string{fmt.Sprintf("%s:%d", m1.config.BindAddr, 23456)})
+	if num != 1 {
+		t.Fatalf("unexpected 1: %d", num)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	// Check the hosts
+	if len(m2.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+
+	if len(m1.Members()) != 2 {
+		t.Fatalf("should have 2 nodes! %v", m2.Members())
+	}
+}
+
+func TestAdvertiseAddr(t *testing.T) {
+	c := testConfig()
+	c.AdvertiseAddr = "127.0.1.100"
+	c.AdvertisePort = 23456
+
+	m, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	yield()
+
+	members := m.Members()
+	if len(members) != 1 {
+		t.Fatalf("bad number of members")
+	}
+
+	if bytes.Compare(members[0].Addr, []byte{127, 0, 1, 100}) != 0 {
+		t.Fatalf("bad: %#v", members[0])
+	}
+
+	if members[0].Port != 23456 {
+		t.Fatalf("bad: %#v", members[0])
+	}
+}
+
+type MockConflict struct {
+	existing *Node
+	other    *Node
+}
+
+func (m *MockConflict) NotifyConflict(existing, other *Node) {
+	m.existing = existing
+	m.other = other
+}
+
+func TestMemberlist_conflictDelegate(t *testing.T) {
+	c1 := testConfig()
+	c2 := testConfig()
+	mock := &MockConflict{}
+	c1.Conflict = mock
+
+	// Ensure name conflict
+	c2.Name = c1.Name
+
+	m1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m1.Shutdown()
+
+	m2, err := Create(c2)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m2.Shutdown()
+
+	_, err = m1.Join([]string{c2.BindAddr})
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	yield()
+
+	// Ensure we were notified
+	if mock.existing == nil || mock.other == nil {
+		t.Fatalf("should get notified")
+	}
+	if mock.existing.Name != mock.other.Name {
+		t.Fatalf("bad: %v %v", mock.existing, mock.other)
+	}
+}
+
+// Consul bug, rapid restart (before failure detection),
+// with an updated meta data. Should be at incarnation 1 for
+// both.
+//
+// This test is uncommented because it requires that either we
+// can rebind the socket (SO_REUSEPORT) which Go does not allow,
+// OR we must disable the address conflict checking in memberlist.
+// I just comment out that code to test this case.
+//
+//func TestMemberlist_Restart_delegateMeta_Update(t *testing.T) {
+//    c1 := testConfig()
+//    c2 := testConfig()
+//    mock1 := &MockDelegate{meta: []byte("web")}
+//    mock2 := &MockDelegate{meta: []byte("lb")}
+//    c1.Delegate = mock1
+//    c2.Delegate = mock2
+
+//    m1, err := Create(c1)
+//    if err != nil {
+//        t.Fatalf("err: %s", err)
+//    }
+//    defer m1.Shutdown()
+
+//    m2, err := Create(c2)
+//    if err != nil {
+//        t.Fatalf("err: %s", err)
+//    }
+//    defer m2.Shutdown()
+
+//    _, err = m1.Join([]string{c2.BindAddr})
+//    if err != nil {
+//        t.Fatalf("err: %s", err)
+//    }
+
+//    yield()
+
+//    // Recreate m1 with updated meta
+//    m1.Shutdown()
+//    c3 := testConfig()
+//    c3.Name = c1.Name
+//    c3.Delegate = mock1
+//    c3.GossipInterval = time.Millisecond
+//    mock1.meta = []byte("api")
+
+//    m1, err = Create(c3)
+//    if err != nil {
+//        t.Fatalf("err: %s", err)
+//    }
+//    defer m1.Shutdown()
+
+//    _, err = m1.Join([]string{c2.BindAddr})
+//    if err != nil {
+//        t.Fatalf("err: %s", err)
+//    }
+
+//    yield()
+//    yield()
+
+//    // Check the updates have propagated
+//    var roles map[string]string
+
+//    // Check the roles of members of m1
+//    m1m := m1.Members()
+//    if len(m1m) != 2 {
+//        t.Fatalf("bad: %#v", m1m)
+//    }
+
+//    roles = make(map[string]string)
+//    for _, m := range m1m {
+//        roles[m.Name] = string(m.Meta)
+//    }
+
+//    if r := roles[c1.Name]; r != "api" {
+//        t.Fatalf("bad role for %s: %s", c1.Name, r)
+//    }
+
+//    if r := roles[c2.Name]; r != "lb" {
+//        t.Fatalf("bad role for %s: %s", c2.Name, r)
+//    }
+
+//    // Check the roles of members of m2
+//    m2m := m2.Members()
+//    if len(m2m) != 2 {
+//        t.Fatalf("bad: %#v", m2m)
+//    }
+
+//    roles = make(map[string]string)
+//    for _, m := range m2m {
+//        roles[m.Name] = string(m.Meta)
+//    }
+
+//    if r := roles[c1.Name]; r != "api" {
+//        t.Fatalf("bad role for %s: %s", c1.Name, r)
+//    }
+
+//    if r := roles[c2.Name]; r != "lb" {
+//        t.Fatalf("bad role for %s: %s", c2.Name, r)
+//    }
+//}

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/merge_delegate.go

@@ -0,0 +1,13 @@
+package memberlist
+
+// MergeDelegate is used to involve a client in
+// a potential cluster merge operation. Namely, when
+// a node does a TCP push/pull (as part of a join),
+// the delegate is involved and allowed to cancel the join
+// based on custom logic. The merge delegate is NOT invoked
+// as part of the push-pull anti-entropy.
+type MergeDelegate interface {
+	// NotifyMerge is invoked when a merge could take place.
+	// Provides a list of the nodes known by the peer.
+	NotifyMerge(peers []*Node) (cancel bool)
+}

+ 852 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/net.go

@@ -0,0 +1,852 @@
+package memberlist
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"net"
+	"time"
+
+	"github.com/armon/go-metrics"
+	"github.com/hashicorp/go-msgpack/codec"
+)
+
+// This is the minimum and maximum protocol version that we can
+// _understand_. We're allowed to speak at any version within this
+// range. This range is inclusive.
+const (
+	ProtocolVersionMin uint8 = 1
+	ProtocolVersionMax       = 2
+)
+
+// messageType is an integer ID of a type of message that can be received
+// on network channels from other members.
+type messageType uint8
+
+// The list of available message types.
+const (
+	pingMsg messageType = iota
+	indirectPingMsg
+	ackRespMsg
+	suspectMsg
+	aliveMsg
+	deadMsg
+	pushPullMsg
+	compoundMsg
+	userMsg // User mesg, not handled by us
+	compressMsg
+	encryptMsg
+)
+
+// compressionType is used to specify the compression algorithm
+type compressionType uint8
+
+const (
+	lzwAlgo compressionType = iota
+)
+
+const (
+	MetaMaxSize            = 512 // Maximum size for node meta data
+	compoundHeaderOverhead = 2   // Assumed header overhead
+	compoundOverhead       = 2   // Assumed overhead per entry in compoundHeader
+	udpBufSize             = 65536
+	udpRecvBuf             = 2 * 1024 * 1024
+	udpSendBuf             = 1400
+	userMsgOverhead        = 1
+	blockingWarning        = 10 * time.Millisecond // Warn if a UDP packet takes this long to process
+	maxPushStateBytes      = 10 * 1024 * 1024
+)
+
+// ping request sent directly to node
+type ping struct {
+	SeqNo uint32
+
+	// Node is sent so the target can verify they are
+	// the intended recipient. This is to protect again an agent
+	// restart with a new name.
+	Node string
+}
+
+// indirect ping sent to an indirect ndoe
+type indirectPingReq struct {
+	SeqNo  uint32
+	Target []byte
+	Port   uint16
+	Node   string
+}
+
+// ack response is sent for a ping
+type ackResp struct {
+	SeqNo uint32
+}
+
+// suspect is broadcast when we suspect a node is dead
+type suspect struct {
+	Incarnation uint32
+	Node        string
+	From        string // Include who is suspecting
+}
+
+// alive is broadcast when we know a node is alive.
+// Overloaded for nodes joining
+type alive struct {
+	Incarnation uint32
+	Node        string
+	Addr        []byte
+	Port        uint16
+	Meta        []byte
+
+	// The versions of the protocol/delegate that are being spoken, order:
+	// pmin, pmax, pcur, dmin, dmax, dcur
+	Vsn []uint8
+}
+
+// dead is broadcast when we confirm a node is dead
+// Overloaded for nodes leaving
+type dead struct {
+	Incarnation uint32
+	Node        string
+	From        string // Include who is suspecting
+}
+
+// pushPullHeader is used to inform the
+// otherside how many states we are transfering
+type pushPullHeader struct {
+	Nodes        int
+	UserStateLen int  // Encodes the byte lengh of user state
+	Join         bool // Is this a join request or a anti-entropy run
+}
+
+// pushNodeState is used for pushPullReq when we are
+// transfering out node states
+type pushNodeState struct {
+	Name        string
+	Addr        []byte
+	Port        uint16
+	Meta        []byte
+	Incarnation uint32
+	State       nodeStateType
+	Vsn         []uint8 // Protocol versions
+}
+
+// compress is used to wrap an underlying payload
+// using a specified compression algorithm
+type compress struct {
+	Algo compressionType
+	Buf  []byte
+}
+
+// msgHandoff is used to transfer a message between goroutines
+type msgHandoff struct {
+	msgType messageType
+	buf     []byte
+	from    net.Addr
+}
+
+// encryptionVersion returns the encryption version to use
+func (m *Memberlist) encryptionVersion() encryptionVersion {
+	switch m.ProtocolVersion() {
+	case 1:
+		return 0
+	default:
+		return 1
+	}
+}
+
+// setUDPRecvBuf is used to resize the UDP receive window. The function
+// attempts to set the read buffer to `udpRecvBuf` but backs off until
+// the read buffer can be set.
+func setUDPRecvBuf(c *net.UDPConn) {
+	size := udpRecvBuf
+	for {
+		if err := c.SetReadBuffer(size); err == nil {
+			break
+		}
+		size = size / 2
+	}
+}
+
+// tcpListen listens for and handles incoming connections
+func (m *Memberlist) tcpListen() {
+	for {
+		conn, err := m.tcpListener.AcceptTCP()
+		if err != nil {
+			if m.shutdown {
+				break
+			}
+			m.logger.Printf("[ERR] memberlist: Error accepting TCP connection: %s", err)
+			continue
+		}
+		go m.handleConn(conn)
+	}
+}
+
+// handleConn handles a single incoming TCP connection
+func (m *Memberlist) handleConn(conn *net.TCPConn) {
+	m.logger.Printf("[DEBUG] memberlist: Responding to push/pull sync with: %s", conn.RemoteAddr())
+	defer conn.Close()
+	metrics.IncrCounter([]string{"memberlist", "tcp", "accept"}, 1)
+
+	join, remoteNodes, userState, err := m.readRemoteState(conn)
+	if err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to receive remote state: %s", err)
+		return
+	}
+
+	if err := m.sendLocalState(conn, join); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to push local state: %s", err)
+	}
+
+	if err := m.verifyProtocol(remoteNodes); err != nil {
+		m.logger.Printf("[ERR] memberlist: Push/pull verification failed: %s", err)
+		return
+	}
+
+	// Invoke the merge delegate if any
+	if join && m.config.Merge != nil {
+		nodes := make([]*Node, len(remoteNodes))
+		for idx, n := range remoteNodes {
+			nodes[idx] = &Node{
+				Name: n.Name,
+				Addr: n.Addr,
+				Port: n.Port,
+				Meta: n.Meta,
+				PMin: n.Vsn[0],
+				PMax: n.Vsn[1],
+				PCur: n.Vsn[2],
+				DMin: n.Vsn[3],
+				DMax: n.Vsn[4],
+				DCur: n.Vsn[5],
+			}
+		}
+		if m.config.Merge.NotifyMerge(nodes) {
+			m.logger.Printf("[WARN] memberlist: Cluster merge canceled")
+			return
+		}
+	}
+
+	// Merge the membership state
+	m.mergeState(remoteNodes)
+
+	// Invoke the delegate for user state
+	if m.config.Delegate != nil {
+		m.config.Delegate.MergeRemoteState(userState, join)
+	}
+}
+
+// udpListen listens for and handles incoming UDP packets
+func (m *Memberlist) udpListen() {
+	var n int
+	var addr net.Addr
+	var err error
+	var lastPacket time.Time
+	for {
+		// Do a check for potentially blocking operations
+		if !lastPacket.IsZero() && time.Now().Sub(lastPacket) > blockingWarning {
+			diff := time.Now().Sub(lastPacket)
+			m.logger.Printf(
+				"[DEBUG] memberlist: Potential blocking operation. Last command took %v",
+				diff)
+		}
+
+		// Create a new buffer
+		// TODO: Use Sync.Pool eventually
+		buf := make([]byte, udpBufSize)
+
+		// Read a packet
+		n, addr, err = m.udpListener.ReadFrom(buf)
+		if err != nil {
+			if m.shutdown {
+				break
+			}
+			m.logger.Printf("[ERR] memberlist: Error reading UDP packet: %s", err)
+			continue
+		}
+
+		// Check the length
+		if n < 1 {
+			m.logger.Printf("[ERR] memberlist: UDP packet too short (%d bytes). From: %s",
+				len(buf), addr)
+			continue
+		}
+
+		// Capture the current time
+		lastPacket = time.Now()
+
+		// Ingest this packet
+		metrics.IncrCounter([]string{"memberlist", "udp", "received"}, float32(n))
+		m.ingestPacket(buf[:n], addr)
+	}
+}
+
+func (m *Memberlist) ingestPacket(buf []byte, from net.Addr) {
+	// Check if encryption is enabled
+	if m.config.EncryptionEnabled() {
+		// Decrypt the payload
+		plain, err := decryptPayload(m.config.Keyring.GetKeys(), buf, nil)
+		if err != nil {
+			m.logger.Printf("[ERR] memberlist: Decrypt packet failed: %v", err)
+			return
+		}
+
+		// Continue processing the plaintext buffer
+		buf = plain
+	}
+
+	// Handle the command
+	m.handleCommand(buf, from)
+}
+
+func (m *Memberlist) handleCommand(buf []byte, from net.Addr) {
+	// Decode the message type
+	msgType := messageType(buf[0])
+	buf = buf[1:]
+
+	// Switch on the msgType
+	switch msgType {
+	case compoundMsg:
+		m.handleCompound(buf, from)
+	case compressMsg:
+		m.handleCompressed(buf, from)
+
+	case pingMsg:
+		m.handlePing(buf, from)
+	case indirectPingMsg:
+		m.handleIndirectPing(buf, from)
+	case ackRespMsg:
+		m.handleAck(buf, from)
+
+	case suspectMsg:
+		fallthrough
+	case aliveMsg:
+		fallthrough
+	case deadMsg:
+		fallthrough
+	case userMsg:
+		select {
+		case m.handoff <- msgHandoff{msgType, buf, from}:
+		default:
+			m.logger.Printf("[WARN] memberlist: UDP handler queue full, dropping message (%d)", msgType)
+		}
+
+	default:
+		m.logger.Printf("[ERR] memberlist: UDP msg type (%d) not supported. From: %s", msgType, from)
+	}
+}
+
+// udpHandler processes messages received over UDP, but is decoupled
+// from the listener to avoid blocking the listener which may cause
+// ping/ack messages to be delayed.
+func (m *Memberlist) udpHandler() {
+	for {
+		select {
+		case msg := <-m.handoff:
+			msgType := msg.msgType
+			buf := msg.buf
+			from := msg.from
+
+			switch msgType {
+			case suspectMsg:
+				m.handleSuspect(buf, from)
+			case aliveMsg:
+				m.handleAlive(buf, from)
+			case deadMsg:
+				m.handleDead(buf, from)
+			case userMsg:
+				m.handleUser(buf, from)
+			default:
+				m.logger.Printf("[ERR] memberlist: UDP msg type (%d) not supported. From: %s (handler)", msgType, from)
+			}
+
+		case <-m.shutdownCh:
+			return
+		}
+	}
+}
+
+func (m *Memberlist) handleCompound(buf []byte, from net.Addr) {
+	// Decode the parts
+	trunc, parts, err := decodeCompoundMessage(buf)
+	if err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode compound request: %s", err)
+		return
+	}
+
+	// Log any truncation
+	if trunc > 0 {
+		m.logger.Printf("[WARN] memberlist: Compound request had %d truncated messages", trunc)
+	}
+
+	// Handle each message
+	for _, part := range parts {
+		m.handleCommand(part, from)
+	}
+}
+
+func (m *Memberlist) handlePing(buf []byte, from net.Addr) {
+	var p ping
+	if err := decode(buf, &p); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode ping request: %s", err)
+		return
+	}
+	// If node is provided, verify that it is for us
+	if p.Node != "" && p.Node != m.config.Name {
+		m.logger.Printf("[WARN] memberlist: Got ping for unexpected node '%s'", p.Node)
+		return
+	}
+	ack := ackResp{p.SeqNo}
+	if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to send ack: %s", err)
+	}
+}
+
+func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) {
+	var ind indirectPingReq
+	if err := decode(buf, &ind); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode indirect ping request: %s", err)
+		return
+	}
+
+	// For proto versions < 2, there is no port provided. Mask old
+	// behavior by using the configured port
+	if m.ProtocolVersion() < 2 || ind.Port == 0 {
+		ind.Port = uint16(m.config.BindPort)
+	}
+
+	// Send a ping to the correct host
+	localSeqNo := m.nextSeqNo()
+	ping := ping{SeqNo: localSeqNo, Node: ind.Node}
+	destAddr := &net.UDPAddr{IP: ind.Target, Port: int(ind.Port)}
+
+	// Setup a response handler to relay the ack
+	respHandler := func() {
+		ack := ackResp{ind.SeqNo}
+		if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
+			m.logger.Printf("[ERR] memberlist: Failed to forward ack: %s", err)
+		}
+	}
+	m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout)
+
+	// Send the ping
+	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to send ping: %s", err)
+	}
+}
+
+func (m *Memberlist) handleAck(buf []byte, from net.Addr) {
+	var ack ackResp
+	if err := decode(buf, &ack); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode ack response: %s", err)
+		return
+	}
+	m.invokeAckHandler(ack.SeqNo)
+}
+
+func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) {
+	var sus suspect
+	if err := decode(buf, &sus); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode suspect message: %s", err)
+		return
+	}
+	m.suspectNode(&sus)
+}
+
+func (m *Memberlist) handleAlive(buf []byte, from net.Addr) {
+	var live alive
+	if err := decode(buf, &live); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode alive message: %s", err)
+		return
+	}
+
+	// For proto versions < 2, there is no port provided. Mask old
+	// behavior by using the configured port
+	if m.ProtocolVersion() < 2 || live.Port == 0 {
+		live.Port = uint16(m.config.BindPort)
+	}
+
+	m.aliveNode(&live, nil, false)
+}
+
+func (m *Memberlist) handleDead(buf []byte, from net.Addr) {
+	var d dead
+	if err := decode(buf, &d); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decode dead message: %s", err)
+		return
+	}
+	m.deadNode(&d)
+}
+
+// handleUser is used to notify channels of incoming user data
+func (m *Memberlist) handleUser(buf []byte, from net.Addr) {
+	d := m.config.Delegate
+	if d != nil {
+		d.NotifyMsg(buf)
+	}
+}
+
+// handleCompressed is used to unpack a compressed message
+func (m *Memberlist) handleCompressed(buf []byte, from net.Addr) {
+	// Try to decode the payload
+	payload, err := decompressPayload(buf)
+	if err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to decompress payload: %v", err)
+		return
+	}
+
+	// Recursively handle the payload
+	m.handleCommand(payload, from)
+}
+
+// encodeAndSendMsg is used to combine the encoding and sending steps
+func (m *Memberlist) encodeAndSendMsg(to net.Addr, msgType messageType, msg interface{}) error {
+	out, err := encode(msgType, msg)
+	if err != nil {
+		return err
+	}
+	if err := m.sendMsg(to, out.Bytes()); err != nil {
+		return err
+	}
+	return nil
+}
+
+// sendMsg is used to send a UDP message to another host. It will opportunistically
+// create a compoundMsg and piggy back other broadcasts
+func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
+	// Check if we can piggy back any messages
+	bytesAvail := udpSendBuf - len(msg) - compoundHeaderOverhead
+	if m.config.EncryptionEnabled() {
+		bytesAvail -= encryptOverhead(m.encryptionVersion())
+	}
+	extra := m.getBroadcasts(compoundOverhead, bytesAvail)
+
+	// Fast path if nothing to piggypack
+	if len(extra) == 0 {
+		return m.rawSendMsg(to, msg)
+	}
+
+	// Join all the messages
+	msgs := make([][]byte, 0, 1+len(extra))
+	msgs = append(msgs, msg)
+	msgs = append(msgs, extra...)
+
+	// Create a compound message
+	compound := makeCompoundMessage(msgs)
+
+	// Send the message
+	return m.rawSendMsg(to, compound.Bytes())
+}
+
+// rawSendMsg is used to send a UDP message to another host without modification
+func (m *Memberlist) rawSendMsg(to net.Addr, msg []byte) error {
+	// Check if we have compression enabled
+	if m.config.EnableCompression {
+		buf, err := compressPayload(msg)
+		if err != nil {
+			m.logger.Printf("[WARN] memberlist: Failed to compress payload: %v", err)
+		} else {
+			// Only use compression if it reduced the size
+			if buf.Len() < len(msg) {
+				msg = buf.Bytes()
+			}
+		}
+	}
+
+	// Check if we have encryption enabled
+	if m.config.EncryptionEnabled() {
+		// Encrypt the payload
+		var buf bytes.Buffer
+		primaryKey := m.config.Keyring.GetPrimaryKey()
+		err := encryptPayload(m.encryptionVersion(), primaryKey, msg, nil, &buf)
+		if err != nil {
+			m.logger.Printf("[ERR] memberlist: Encryption of message failed: %v", err)
+			return err
+		}
+		msg = buf.Bytes()
+	}
+
+	metrics.IncrCounter([]string{"memberlist", "udp", "sent"}, float32(len(msg)))
+	_, err := m.udpListener.WriteTo(msg, to)
+	return err
+}
+
+// sendState is used to initiate a push/pull over TCP with a remote node
+func (m *Memberlist) sendAndReceiveState(addr []byte, port uint16, join bool) ([]pushNodeState, []byte, error) {
+	// Attempt to connect
+	dialer := net.Dialer{Timeout: m.config.TCPTimeout}
+	dest := net.TCPAddr{IP: addr, Port: int(port)}
+	conn, err := dialer.Dial("tcp", dest.String())
+	if err != nil {
+		return nil, nil, err
+	}
+	defer conn.Close()
+	m.logger.Printf("[DEBUG] memberlist: Initiating push/pull sync with: %s", conn.RemoteAddr())
+	metrics.IncrCounter([]string{"memberlist", "tcp", "connect"}, 1)
+
+	// Send our state
+	if err := m.sendLocalState(conn, join); err != nil {
+		return nil, nil, err
+	}
+
+	// Read remote state
+	_, remote, userState, err := m.readRemoteState(conn)
+	if err != nil {
+		err := fmt.Errorf("Reading remote state failed: %v", err)
+		return nil, nil, err
+	}
+
+	// Return the remote state
+	return remote, userState, nil
+}
+
+// sendLocalState is invoked to send our local state over a tcp connection
+func (m *Memberlist) sendLocalState(conn net.Conn, join bool) error {
+	// Setup a deadline
+	conn.SetDeadline(time.Now().Add(m.config.TCPTimeout))
+
+	// Prepare the local node state
+	m.nodeLock.RLock()
+	localNodes := make([]pushNodeState, len(m.nodes))
+	for idx, n := range m.nodes {
+		localNodes[idx].Name = n.Name
+		localNodes[idx].Addr = n.Addr
+		localNodes[idx].Port = n.Port
+		localNodes[idx].Incarnation = n.Incarnation
+		localNodes[idx].State = n.State
+		localNodes[idx].Meta = n.Meta
+		localNodes[idx].Vsn = []uint8{
+			n.PMin, n.PMax, n.PCur,
+			n.DMin, n.DMax, n.DCur,
+		}
+	}
+	m.nodeLock.RUnlock()
+
+	// Get the delegate state
+	var userData []byte
+	if m.config.Delegate != nil {
+		userData = m.config.Delegate.LocalState(join)
+	}
+
+	// Create a bytes buffer writer
+	bufConn := bytes.NewBuffer(nil)
+
+	// Send our node state
+	header := pushPullHeader{Nodes: len(localNodes), UserStateLen: len(userData), Join: join}
+	hd := codec.MsgpackHandle{}
+	enc := codec.NewEncoder(bufConn, &hd)
+
+	// Begin state push
+	if _, err := bufConn.Write([]byte{byte(pushPullMsg)}); err != nil {
+		return err
+	}
+
+	if err := enc.Encode(&header); err != nil {
+		return err
+	}
+	for i := 0; i < header.Nodes; i++ {
+		if err := enc.Encode(&localNodes[i]); err != nil {
+			return err
+		}
+	}
+
+	// Write the user state as well
+	if userData != nil {
+		if _, err := bufConn.Write(userData); err != nil {
+			return err
+		}
+	}
+
+	// Get the send buffer
+	sendBuf := bufConn.Bytes()
+
+	// Check if compresion is enabled
+	if m.config.EnableCompression {
+		compBuf, err := compressPayload(bufConn.Bytes())
+		if err != nil {
+			m.logger.Printf("[ERROR] memberlist: Failed to compress local state: %v", err)
+		} else {
+			sendBuf = compBuf.Bytes()
+		}
+	}
+
+	// Check if encryption is enabled
+	if m.config.EncryptionEnabled() {
+		crypt, err := m.encryptLocalState(sendBuf)
+		if err != nil {
+			m.logger.Printf("[ERROR] memberlist: Failed to encrypt local state: %v", err)
+			return err
+		}
+		sendBuf = crypt
+	}
+
+	// Write out the entire send buffer
+	metrics.IncrCounter([]string{"memberlist", "tcp", "sent"}, float32(len(sendBuf)))
+	if _, err := conn.Write(sendBuf); err != nil {
+		return err
+	}
+	return nil
+}
+
+// encryptLocalState is used to help encrypt local state before sending
+func (m *Memberlist) encryptLocalState(sendBuf []byte) ([]byte, error) {
+	var buf bytes.Buffer
+
+	// Write the encryptMsg byte
+	buf.WriteByte(byte(encryptMsg))
+
+	// Write the size of the message
+	sizeBuf := make([]byte, 4)
+	encVsn := m.encryptionVersion()
+	encLen := encryptedLength(encVsn, len(sendBuf))
+	binary.BigEndian.PutUint32(sizeBuf, uint32(encLen))
+	buf.Write(sizeBuf)
+
+	// Write the encrypted cipher text to the buffer
+	key := m.config.Keyring.GetPrimaryKey()
+	err := encryptPayload(encVsn, key, sendBuf, buf.Bytes()[:5], &buf)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
+// decryptRemoteState is used to help decrypt the remote state
+func (m *Memberlist) decryptRemoteState(bufConn io.Reader) ([]byte, error) {
+	// Read in enough to determine message length
+	cipherText := bytes.NewBuffer(nil)
+	cipherText.WriteByte(byte(encryptMsg))
+	_, err := io.CopyN(cipherText, bufConn, 4)
+	if err != nil {
+		return nil, err
+	}
+
+	// Ensure we aren't asked to download too much. This is to guard against
+	// an attack vector where a huge amount of state is sent
+	moreBytes := binary.BigEndian.Uint32(cipherText.Bytes()[1:5])
+	if moreBytes > maxPushStateBytes {
+		return nil, fmt.Errorf("Remote node state is larger than limit (%d)", moreBytes)
+	}
+
+	// Read in the rest of the payload
+	_, err = io.CopyN(cipherText, bufConn, int64(moreBytes))
+	if err != nil {
+		return nil, err
+	}
+
+	// Decrypt the cipherText
+	dataBytes := cipherText.Bytes()[:5]
+	cipherBytes := cipherText.Bytes()[5:]
+
+	// Decrypt the payload
+	keys := m.config.Keyring.GetKeys()
+	return decryptPayload(keys, cipherBytes, dataBytes)
+}
+
+// recvRemoteState is used to read the remote state from a connection
+func (m *Memberlist) readRemoteState(conn net.Conn) (bool, []pushNodeState, []byte, error) {
+	// Setup a deadline
+	conn.SetDeadline(time.Now().Add(m.config.TCPTimeout))
+
+	// Created a buffered reader
+	var bufConn io.Reader = bufio.NewReader(conn)
+
+	// Read the message type
+	buf := [1]byte{0}
+	if _, err := bufConn.Read(buf[:]); err != nil {
+		return false, nil, nil, err
+	}
+	msgType := messageType(buf[0])
+
+	// Check if the message is encrypted
+	if msgType == encryptMsg {
+		if !m.config.EncryptionEnabled() {
+			return false, nil, nil,
+				fmt.Errorf("Remote state is encrypted and encryption is not configured")
+		}
+
+		plain, err := m.decryptRemoteState(bufConn)
+		if err != nil {
+			return false, nil, nil, err
+		}
+
+		// Reset message type and bufConn
+		msgType = messageType(plain[0])
+		bufConn = bytes.NewReader(plain[1:])
+	} else if m.config.EncryptionEnabled() {
+		return false, nil, nil,
+			fmt.Errorf("Encryption is configured but remote state is not encrypted")
+	}
+
+	// Get the msgPack decoders
+	hd := codec.MsgpackHandle{}
+	dec := codec.NewDecoder(bufConn, &hd)
+
+	// Check if we have a compressed message
+	if msgType == compressMsg {
+		var c compress
+		if err := dec.Decode(&c); err != nil {
+			return false, nil, nil, err
+		}
+		decomp, err := decompressBuffer(&c)
+		if err != nil {
+			return false, nil, nil, err
+		}
+
+		// Reset the message type
+		msgType = messageType(decomp[0])
+
+		// Create a new bufConn
+		bufConn = bytes.NewReader(decomp[1:])
+
+		// Create a new decoder
+		dec = codec.NewDecoder(bufConn, &hd)
+	}
+
+	// Quit if not push/pull
+	if msgType != pushPullMsg {
+		err := fmt.Errorf("received invalid msgType (%d)", msgType)
+		return false, nil, nil, err
+	}
+
+	// Read the push/pull header
+	var header pushPullHeader
+	if err := dec.Decode(&header); err != nil {
+		return false, nil, nil, err
+	}
+
+	// Allocate space for the transfer
+	remoteNodes := make([]pushNodeState, header.Nodes)
+
+	// Try to decode all the states
+	for i := 0; i < header.Nodes; i++ {
+		if err := dec.Decode(&remoteNodes[i]); err != nil {
+			return false, remoteNodes, nil, err
+		}
+	}
+
+	// Read the remote user state into a buffer
+	var userBuf []byte
+	if header.UserStateLen > 0 {
+		userBuf = make([]byte, header.UserStateLen)
+		bytes, err := io.ReadAtLeast(bufConn, userBuf, header.UserStateLen)
+		if err == nil && bytes != header.UserStateLen {
+			err = fmt.Errorf(
+				"Failed to read full user state (%d / %d)",
+				bytes, header.UserStateLen)
+		}
+		if err != nil {
+			return false, remoteNodes, nil, err
+		}
+	}
+
+	// For proto versions < 2, there is no port provided. Mask old
+	// behavior by using the configured port
+	for idx := range remoteNodes {
+		if m.ProtocolVersion() < 2 || remoteNodes[idx].Port == 0 {
+			remoteNodes[idx].Port = uint16(m.config.BindPort)
+		}
+	}
+
+	return header.Join, remoteNodes, userBuf, nil
+}

+ 476 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/net_test.go

@@ -0,0 +1,476 @@
+package memberlist
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"github.com/hashicorp/go-msgpack/codec"
+	"io"
+	"net"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestHandleCompoundPing(t *testing.T) {
+	m := GetMemberlist(t)
+	m.config.EnableCompression = false
+	defer m.Shutdown()
+
+	var udp *net.UDPConn
+	for port := 60000; port < 61000; port++ {
+		udpAddr := fmt.Sprintf("127.0.0.1:%d", port)
+		udpLn, err := net.ListenPacket("udp", udpAddr)
+		if err == nil {
+			udp = udpLn.(*net.UDPConn)
+			break
+		}
+	}
+
+	if udp == nil {
+		t.Fatalf("no udp listener")
+	}
+
+	// Encode a ping
+	ping := ping{SeqNo: 42}
+	buf, err := encode(pingMsg, ping)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Make a compound message
+	compound := makeCompoundMessage([][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()})
+
+	// Send compound version
+	addr := &net.UDPAddr{IP: net.ParseIP(m.config.BindAddr), Port: m.config.BindPort}
+	udp.WriteTo(compound.Bytes(), addr)
+
+	// Wait for responses
+	go func() {
+		time.Sleep(time.Second)
+		panic("timeout")
+	}()
+
+	for i := 0; i < 3; i++ {
+		in := make([]byte, 1500)
+		n, _, err := udp.ReadFrom(in)
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		in = in[0:n]
+
+		msgType := messageType(in[0])
+		if msgType != ackRespMsg {
+			t.Fatalf("bad response %v", in)
+		}
+
+		var ack ackResp
+		if err := decode(in[1:], &ack); err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+
+		if ack.SeqNo != 42 {
+			t.Fatalf("bad sequence no")
+		}
+	}
+}
+
+func TestHandlePing(t *testing.T) {
+	m := GetMemberlist(t)
+	m.config.EnableCompression = false
+	defer m.Shutdown()
+
+	var udp *net.UDPConn
+	for port := 60000; port < 61000; port++ {
+		udpAddr := fmt.Sprintf("127.0.0.1:%d", port)
+		udpLn, err := net.ListenPacket("udp", udpAddr)
+		if err == nil {
+			udp = udpLn.(*net.UDPConn)
+			break
+		}
+	}
+
+	if udp == nil {
+		t.Fatalf("no udp listener")
+	}
+
+	// Encode a ping
+	ping := ping{SeqNo: 42}
+	buf, err := encode(pingMsg, ping)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Send
+	addr := &net.UDPAddr{IP: net.ParseIP(m.config.BindAddr), Port: m.config.BindPort}
+	udp.WriteTo(buf.Bytes(), addr)
+
+	// Wait for response
+	go func() {
+		time.Sleep(time.Second)
+		panic("timeout")
+	}()
+
+	in := make([]byte, 1500)
+	n, _, err := udp.ReadFrom(in)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+	in = in[0:n]
+
+	msgType := messageType(in[0])
+	if msgType != ackRespMsg {
+		t.Fatalf("bad response %v", in)
+	}
+
+	var ack ackResp
+	if err := decode(in[1:], &ack); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	if ack.SeqNo != 42 {
+		t.Fatalf("bad sequence no")
+	}
+}
+
+func TestHandlePing_WrongNode(t *testing.T) {
+	m := GetMemberlist(t)
+	m.config.EnableCompression = false
+	defer m.Shutdown()
+
+	var udp *net.UDPConn
+	for port := 60000; port < 61000; port++ {
+		udpAddr := fmt.Sprintf("127.0.0.1:%d", port)
+		udpLn, err := net.ListenPacket("udp", udpAddr)
+		if err == nil {
+			udp = udpLn.(*net.UDPConn)
+			break
+		}
+	}
+
+	if udp == nil {
+		t.Fatalf("no udp listener")
+	}
+
+	// Encode a ping, wrong node!
+	ping := ping{SeqNo: 42, Node: m.config.Name + "-bad"}
+	buf, err := encode(pingMsg, ping)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Send
+	addr := &net.UDPAddr{IP: net.ParseIP(m.config.BindAddr), Port: m.config.BindPort}
+	udp.WriteTo(buf.Bytes(), addr)
+
+	// Wait for response
+	udp.SetDeadline(time.Now().Add(50 * time.Millisecond))
+	in := make([]byte, 1500)
+	_, _, err = udp.ReadFrom(in)
+
+	// Should get an i/o timeout
+	if err == nil {
+		t.Fatalf("expected err %s", err)
+	}
+}
+
+func TestHandleIndirectPing(t *testing.T) {
+	m := GetMemberlist(t)
+	m.config.EnableCompression = false
+	defer m.Shutdown()
+
+	var udp *net.UDPConn
+	for port := 60000; port < 61000; port++ {
+		udpAddr := fmt.Sprintf("127.0.0.1:%d", port)
+		udpLn, err := net.ListenPacket("udp", udpAddr)
+		if err == nil {
+			udp = udpLn.(*net.UDPConn)
+			break
+		}
+	}
+
+	if udp == nil {
+		t.Fatalf("no udp listener")
+	}
+
+	// Encode an indirect ping
+	ind := indirectPingReq{
+		SeqNo:  100,
+		Target: net.ParseIP(m.config.BindAddr),
+		Port:   uint16(m.config.BindPort),
+	}
+	buf, err := encode(indirectPingMsg, &ind)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Send
+	addr := &net.UDPAddr{IP: net.ParseIP(m.config.BindAddr), Port: m.config.BindPort}
+	udp.WriteTo(buf.Bytes(), addr)
+
+	// Wait for response
+	go func() {
+		time.Sleep(time.Second)
+		panic("timeout")
+	}()
+
+	in := make([]byte, 1500)
+	n, _, err := udp.ReadFrom(in)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+	in = in[0:n]
+
+	msgType := messageType(in[0])
+	if msgType != ackRespMsg {
+		t.Fatalf("bad response %v", in)
+	}
+
+	var ack ackResp
+	if err := decode(in[1:], &ack); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	if ack.SeqNo != 100 {
+		t.Fatalf("bad sequence no")
+	}
+}
+
+func TestTCPPushPull(t *testing.T) {
+	m := GetMemberlist(t)
+	defer m.Shutdown()
+	m.nodes = append(m.nodes, &nodeState{
+		Node: Node{
+			Name: "Test 0",
+			Addr: net.ParseIP(m.config.BindAddr),
+			Port: uint16(m.config.BindPort),
+		},
+		Incarnation: 0,
+		State:       stateSuspect,
+		StateChange: time.Now().Add(-1 * time.Second),
+	})
+
+	addr := fmt.Sprintf("%s:%d", m.config.BindAddr, m.config.BindPort)
+	conn, err := net.Dial("tcp", addr)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+	defer conn.Close()
+
+	localNodes := make([]pushNodeState, 3)
+	localNodes[0].Name = "Test 0"
+	localNodes[0].Addr = net.ParseIP(m.config.BindAddr)
+	localNodes[0].Port = uint16(m.config.BindPort)
+	localNodes[0].Incarnation = 1
+	localNodes[0].State = stateAlive
+	localNodes[1].Name = "Test 1"
+	localNodes[1].Addr = net.ParseIP(m.config.BindAddr)
+	localNodes[1].Port = uint16(m.config.BindPort)
+	localNodes[1].Incarnation = 1
+	localNodes[1].State = stateAlive
+	localNodes[2].Name = "Test 2"
+	localNodes[2].Addr = net.ParseIP(m.config.BindAddr)
+	localNodes[2].Port = uint16(m.config.BindPort)
+	localNodes[2].Incarnation = 1
+	localNodes[2].State = stateAlive
+
+	// Send our node state
+	header := pushPullHeader{Nodes: 3}
+	hd := codec.MsgpackHandle{}
+	enc := codec.NewEncoder(conn, &hd)
+
+	// Send the push/pull indicator
+	conn.Write([]byte{byte(pushPullMsg)})
+
+	if err := enc.Encode(&header); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+	for i := 0; i < header.Nodes; i++ {
+		if err := enc.Encode(&localNodes[i]); err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+	}
+
+	// Read the message type
+	var msgType messageType
+	if err := binary.Read(conn, binary.BigEndian, &msgType); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	var bufConn io.Reader = conn
+	msghd := codec.MsgpackHandle{}
+	dec := codec.NewDecoder(bufConn, &msghd)
+
+	// Check if we have a compressed message
+	if msgType == compressMsg {
+		var c compress
+		if err := dec.Decode(&c); err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+		decomp, err := decompressBuffer(&c)
+		if err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+
+		// Reset the message type
+		msgType = messageType(decomp[0])
+
+		// Create a new bufConn
+		bufConn = bytes.NewReader(decomp[1:])
+
+		// Create a new decoder
+		dec = codec.NewDecoder(bufConn, &hd)
+	}
+
+	// Quit if not push/pull
+	if msgType != pushPullMsg {
+		t.Fatalf("bad message type")
+	}
+
+	if err := dec.Decode(&header); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Allocate space for the transfer
+	remoteNodes := make([]pushNodeState, header.Nodes)
+
+	// Try to decode all the states
+	for i := 0; i < header.Nodes; i++ {
+		if err := dec.Decode(&remoteNodes[i]); err != nil {
+			t.Fatalf("unexpected err %s", err)
+		}
+	}
+
+	if len(remoteNodes) != 1 {
+		t.Fatalf("bad response")
+	}
+
+	n := &remoteNodes[0]
+	if n.Name != "Test 0" {
+		t.Fatalf("bad name")
+	}
+	if bytes.Compare(n.Addr, net.ParseIP(m.config.BindAddr)) != 0 {
+		t.Fatal("bad addr")
+	}
+	if n.Incarnation != 0 {
+		t.Fatal("bad incarnation")
+	}
+	if n.State != stateSuspect {
+		t.Fatal("bad state")
+	}
+}
+
+func TestSendMsg_Piggyback(t *testing.T) {
+	m := GetMemberlist(t)
+	defer m.Shutdown()
+
+	// Add a message to be broadcast
+	a := alive{
+		Incarnation: 10,
+		Node:        "rand",
+		Addr:        []byte{127, 0, 0, 255},
+		Meta:        nil,
+	}
+	m.encodeAndBroadcast("rand", aliveMsg, &a)
+
+	var udp *net.UDPConn
+	for port := 60000; port < 61000; port++ {
+		udpAddr := fmt.Sprintf("127.0.0.1:%d", port)
+		udpLn, err := net.ListenPacket("udp", udpAddr)
+		if err == nil {
+			udp = udpLn.(*net.UDPConn)
+			break
+		}
+	}
+
+	// Encode a ping
+	ping := ping{SeqNo: 42}
+	buf, err := encode(pingMsg, ping)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	// Send
+	addr := &net.UDPAddr{IP: net.ParseIP(m.config.BindAddr), Port: m.config.BindPort}
+	udp.WriteTo(buf.Bytes(), addr)
+
+	// Wait for response
+	go func() {
+		time.Sleep(time.Second)
+		panic("timeout")
+	}()
+
+	in := make([]byte, 1500)
+	n, _, err := udp.ReadFrom(in)
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+	in = in[0:n]
+
+	msgType := messageType(in[0])
+	if msgType != compoundMsg {
+		t.Fatalf("bad response %v", in)
+	}
+
+	// get the parts
+	trunc, parts, err := decodeCompoundMessage(in[1:])
+	if trunc != 0 {
+		t.Fatalf("unexpected truncation")
+	}
+	if len(parts) != 2 {
+		t.Fatalf("unexpected parts %v", parts)
+	}
+	if err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	var ack ackResp
+	if err := decode(parts[0][1:], &ack); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	if ack.SeqNo != 42 {
+		t.Fatalf("bad sequence no")
+	}
+
+	var aliveout alive
+	if err := decode(parts[1][1:], &aliveout); err != nil {
+		t.Fatalf("unexpected err %s", err)
+	}
+
+	if aliveout.Node != "rand" || aliveout.Incarnation != 10 {
+		t.Fatalf("bad mesg")
+	}
+}
+
+func TestEncryptDecryptState(t *testing.T) {
+	state := []byte("this is our internal state...")
+	config := &Config{
+		SecretKey:       []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+		ProtocolVersion: ProtocolVersionMax,
+	}
+
+	m, err := Create(config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer m.Shutdown()
+
+	crypt, err := m.encryptLocalState(state)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Create reader, seek past the type byte
+	buf := bytes.NewReader(crypt)
+	buf.Seek(1, 0)
+
+	plain, err := m.decryptRemoteState(buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if !reflect.DeepEqual(state, plain) {
+		t.Fatalf("Decrypt failed: %v", plain)
+	}
+}

+ 167 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/queue.go

@@ -0,0 +1,167 @@
+package memberlist
+
+import (
+	"sort"
+	"sync"
+)
+
+// TransmitLimitedQueue is used to queue messages to broadcast to
+// the cluster (via gossip) but limits the number of transmits per
+// message. It also prioritizes messages with lower transmit counts
+// (hence newer messages).
+type TransmitLimitedQueue struct {
+	// NumNodes returns the number of nodes in the cluster. This is
+	// used to determine the retransmit count, which is calculated
+	// based on the log of this.
+	NumNodes func() int
+
+	// RetransmitMult is the multiplier used to determine the maximum
+	// number of retransmissions attempted.
+	RetransmitMult int
+
+	sync.Mutex
+	bcQueue limitedBroadcasts
+}
+
+type limitedBroadcast struct {
+	transmits int // Number of transmissions attempted.
+	b         Broadcast
+}
+type limitedBroadcasts []*limitedBroadcast
+
+// Broadcast is something that can be broadcasted via gossip to
+// the memberlist cluster.
+type Broadcast interface {
+	// Invalidates checks if enqueuing the current broadcast
+	// invalidates a previous broadcast
+	Invalidates(b Broadcast) bool
+
+	// Returns a byte form of the message
+	Message() []byte
+
+	// Finished is invoked when the message will no longer
+	// be broadcast, either due to invalidation or to the
+	// transmit limit being reached
+	Finished()
+}
+
+// QueueBroadcast is used to enqueue a broadcast
+func (q *TransmitLimitedQueue) QueueBroadcast(b Broadcast) {
+	q.Lock()
+	defer q.Unlock()
+
+	// Check if this message invalidates another
+	n := len(q.bcQueue)
+	for i := 0; i < n; i++ {
+		if b.Invalidates(q.bcQueue[i].b) {
+			q.bcQueue[i].b.Finished()
+			copy(q.bcQueue[i:], q.bcQueue[i+1:])
+			q.bcQueue[n-1] = nil
+			q.bcQueue = q.bcQueue[:n-1]
+			n--
+		}
+	}
+
+	// Append to the queue
+	q.bcQueue = append(q.bcQueue, &limitedBroadcast{0, b})
+}
+
+// GetBroadcasts is used to get a number of broadcasts, up to a byte limit
+// and applying a per-message overhead as provided.
+func (q *TransmitLimitedQueue) GetBroadcasts(overhead, limit int) [][]byte {
+	q.Lock()
+	defer q.Unlock()
+
+	// Fast path the default case
+	if len(q.bcQueue) == 0 {
+		return nil
+	}
+
+	transmitLimit := retransmitLimit(q.RetransmitMult, q.NumNodes())
+	bytesUsed := 0
+	var toSend [][]byte
+
+	for i := len(q.bcQueue) - 1; i >= 0; i-- {
+		// Check if this is within our limits
+		b := q.bcQueue[i]
+		msg := b.b.Message()
+		if bytesUsed+overhead+len(msg) > limit {
+			continue
+		}
+
+		// Add to slice to send
+		bytesUsed += overhead + len(msg)
+		toSend = append(toSend, msg)
+
+		// Check if we should stop transmission
+		b.transmits++
+		if b.transmits >= transmitLimit {
+			b.b.Finished()
+			n := len(q.bcQueue)
+			q.bcQueue[i], q.bcQueue[n-1] = q.bcQueue[n-1], nil
+			q.bcQueue = q.bcQueue[:n-1]
+		}
+	}
+
+	// If we are sending anything, we need to re-sort to deal
+	// with adjusted transmit counts
+	if len(toSend) > 0 {
+		q.bcQueue.Sort()
+	}
+	return toSend
+}
+
+// NumQueued returns the number of queued messages
+func (q *TransmitLimitedQueue) NumQueued() int {
+	q.Lock()
+	defer q.Unlock()
+	return len(q.bcQueue)
+}
+
+// Reset clears all the queued messages
+func (q *TransmitLimitedQueue) Reset() {
+	q.Lock()
+	defer q.Unlock()
+	for _, b := range q.bcQueue {
+		b.b.Finished()
+	}
+	q.bcQueue = nil
+}
+
+// Prune will retain the maxRetain latest messages, and the rest
+// will be discarded. This can be used to prevent unbounded queue sizes
+func (q *TransmitLimitedQueue) Prune(maxRetain int) {
+	q.Lock()
+	defer q.Unlock()
+
+	// Do nothing if queue size is less than the limit
+	n := len(q.bcQueue)
+	if n < maxRetain {
+		return
+	}
+
+	// Invalidate the messages we will be removing
+	for i := 0; i < n-maxRetain; i++ {
+		q.bcQueue[i].b.Finished()
+	}
+
+	// Move the messages, and retain only the last maxRetain
+	copy(q.bcQueue[0:], q.bcQueue[n-maxRetain:])
+	q.bcQueue = q.bcQueue[:maxRetain]
+}
+
+func (b limitedBroadcasts) Len() int {
+	return len(b)
+}
+
+func (b limitedBroadcasts) Less(i, j int) bool {
+	return b[i].transmits < b[j].transmits
+}
+
+func (b limitedBroadcasts) Swap(i, j int) {
+	b[i], b[j] = b[j], b[i]
+}
+
+func (b limitedBroadcasts) Sort() {
+	sort.Sort(sort.Reverse(b))
+}

+ 172 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/queue_test.go

@@ -0,0 +1,172 @@
+package memberlist
+
+import (
+	"testing"
+)
+
+func TestTransmitLimited_Queue(t *testing.T) {
+	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 1 }}
+	q.QueueBroadcast(&memberlistBroadcast{"test", nil, nil})
+	q.QueueBroadcast(&memberlistBroadcast{"foo", nil, nil})
+	q.QueueBroadcast(&memberlistBroadcast{"bar", nil, nil})
+
+	if len(q.bcQueue) != 3 {
+		t.Fatalf("bad len")
+	}
+	if q.bcQueue[0].b.(*memberlistBroadcast).node != "test" {
+		t.Fatalf("missing test")
+	}
+	if q.bcQueue[1].b.(*memberlistBroadcast).node != "foo" {
+		t.Fatalf("missing foo")
+	}
+	if q.bcQueue[2].b.(*memberlistBroadcast).node != "bar" {
+		t.Fatalf("missing bar")
+	}
+
+	// Should invalidate previous message
+	q.QueueBroadcast(&memberlistBroadcast{"test", nil, nil})
+
+	if len(q.bcQueue) != 3 {
+		t.Fatalf("bad len")
+	}
+	if q.bcQueue[0].b.(*memberlistBroadcast).node != "foo" {
+		t.Fatalf("missing foo")
+	}
+	if q.bcQueue[1].b.(*memberlistBroadcast).node != "bar" {
+		t.Fatalf("missing bar")
+	}
+	if q.bcQueue[2].b.(*memberlistBroadcast).node != "test" {
+		t.Fatalf("missing test")
+	}
+}
+
+func TestTransmitLimited_GetBroadcasts(t *testing.T) {
+	q := &TransmitLimitedQueue{RetransmitMult: 3, NumNodes: func() int { return 10 }}
+
+	// 18 bytes per message
+	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
+
+	// 2 byte overhead per message, should get all 4 messages
+	all := q.GetBroadcasts(2, 80)
+	if len(all) != 4 {
+		t.Fatalf("missing messages: %v", all)
+	}
+
+	// 3 byte overhead, should only get 3 messages back
+	partial := q.GetBroadcasts(3, 80)
+	if len(partial) != 3 {
+		t.Fatalf("missing messages: %v", partial)
+	}
+}
+
+func TestTransmitLimited_GetBroadcasts_Limit(t *testing.T) {
+	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 10 }}
+
+	// 18 bytes per message
+	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
+
+	// 3 byte overhead, should only get 3 messages back
+	partial1 := q.GetBroadcasts(3, 80)
+	if len(partial1) != 3 {
+		t.Fatalf("missing messages: %v", partial1)
+	}
+
+	partial2 := q.GetBroadcasts(3, 80)
+	if len(partial2) != 3 {
+		t.Fatalf("missing messages: %v", partial2)
+	}
+
+	// Only two not expired
+	partial3 := q.GetBroadcasts(3, 80)
+	if len(partial3) != 2 {
+		t.Fatalf("missing messages: %v", partial3)
+	}
+
+	// Should get nothing
+	partial5 := q.GetBroadcasts(3, 80)
+	if len(partial5) != 0 {
+		t.Fatalf("missing messages: %v", partial5)
+	}
+}
+
+func TestTransmitLimited_Prune(t *testing.T) {
+	q := &TransmitLimitedQueue{RetransmitMult: 1, NumNodes: func() int { return 10 }}
+
+	ch1 := make(chan struct{}, 1)
+	ch2 := make(chan struct{}, 1)
+
+	// 18 bytes per message
+	q.QueueBroadcast(&memberlistBroadcast{"test", []byte("1. this is a test."), ch1})
+	q.QueueBroadcast(&memberlistBroadcast{"foo", []byte("2. this is a test."), ch2})
+	q.QueueBroadcast(&memberlistBroadcast{"bar", []byte("3. this is a test."), nil})
+	q.QueueBroadcast(&memberlistBroadcast{"baz", []byte("4. this is a test."), nil})
+
+	// Keep only 2
+	q.Prune(2)
+
+	if q.NumQueued() != 2 {
+		t.Fatalf("bad len")
+	}
+
+	// Should notify the first two
+	select {
+	case <-ch1:
+	default:
+		t.Fatalf("expected invalidation")
+	}
+	select {
+	case <-ch2:
+	default:
+		t.Fatalf("expected invalidation")
+	}
+
+	if q.bcQueue[0].b.(*memberlistBroadcast).node != "bar" {
+		t.Fatalf("missing bar")
+	}
+	if q.bcQueue[1].b.(*memberlistBroadcast).node != "baz" {
+		t.Fatalf("missing baz")
+	}
+}
+
+func TestLimitedBroadcastSort(t *testing.T) {
+	bc := limitedBroadcasts([]*limitedBroadcast{
+		&limitedBroadcast{
+			transmits: 0,
+		},
+		&limitedBroadcast{
+			transmits: 10,
+		},
+		&limitedBroadcast{
+			transmits: 3,
+		},
+		&limitedBroadcast{
+			transmits: 4,
+		},
+		&limitedBroadcast{
+			transmits: 7,
+		},
+	})
+	bc.Sort()
+
+	if bc[0].transmits != 10 {
+		t.Fatalf("bad val %v", bc[0])
+	}
+	if bc[1].transmits != 7 {
+		t.Fatalf("bad val %v", bc[7])
+	}
+	if bc[2].transmits != 4 {
+		t.Fatalf("bad val %v", bc[2])
+	}
+	if bc[3].transmits != 3 {
+		t.Fatalf("bad val %v", bc[3])
+	}
+	if bc[4].transmits != 0 {
+		t.Fatalf("bad val %v", bc[4])
+	}
+}

+ 198 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/security.go

@@ -0,0 +1,198 @@
+package memberlist
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"fmt"
+	"io"
+)
+
+/*
+
+Encrypted messages are prefixed with an encryptionVersion byte
+that is used for us to be able to properly encode/decode. We
+currently support the following versions:
+
+ 0 - AES-GCM 128, using PKCS7 padding
+ 1 - AES-GCM 128, no padding. Padding not needed, caused bloat.
+
+*/
+type encryptionVersion uint8
+
+const (
+	minEncryptionVersion encryptionVersion = 0
+	maxEncryptionVersion encryptionVersion = 1
+)
+
+const (
+	versionSize    = 1
+	nonceSize      = 12
+	tagSize        = 16
+	maxPadOverhead = 16
+	blockSize      = aes.BlockSize
+)
+
+// pkcs7encode is used to pad a byte buffer to a specific block size using
+// the PKCS7 algorithm. "Ignores" some bytes to compensate for IV
+func pkcs7encode(buf *bytes.Buffer, ignore, blockSize int) {
+	n := buf.Len() - ignore
+	more := blockSize - (n % blockSize)
+	for i := 0; i < more; i++ {
+		buf.WriteByte(byte(more))
+	}
+}
+
+// pkcs7decode is used to decode a buffer that has been padded
+func pkcs7decode(buf []byte, blockSize int) []byte {
+	if len(buf) == 0 {
+		panic("Cannot decode a PKCS7 buffer of zero length")
+	}
+	n := len(buf)
+	last := buf[n-1]
+	n -= int(last)
+	return buf[:n]
+}
+
+// encryptOverhead returns the maximum possible overhead of encryption by version
+func encryptOverhead(vsn encryptionVersion) int {
+	switch vsn {
+	case 0:
+		return 45 // Version: 1, IV: 12, Padding: 16, Tag: 16
+	case 1:
+		return 29 // Version: 1, IV: 12, Tag: 16
+	default:
+		panic("unsupported version")
+	}
+}
+
+// encryptedLength is used to compute the buffer size needed
+// for a message of given length
+func encryptedLength(vsn encryptionVersion, inp int) int {
+	// If we are on version 1, there is no padding
+	if vsn >= 1 {
+		return versionSize + nonceSize + inp + tagSize
+	}
+
+	// Determine the padding size
+	padding := blockSize - (inp % blockSize)
+
+	// Sum the extra parts to get total size
+	return versionSize + nonceSize + inp + padding + tagSize
+}
+
+// encryptPayload is used to encrypt a message with a given key.
+// We make use of AES-128 in GCM mode. New byte buffer is the version,
+// nonce, ciphertext and tag
+func encryptPayload(vsn encryptionVersion, key []byte, msg []byte, data []byte, dst *bytes.Buffer) error {
+	// Get the AES block cipher
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return err
+	}
+
+	// Get the GCM cipher mode
+	gcm, err := cipher.NewGCM(aesBlock)
+	if err != nil {
+		return err
+	}
+
+	// Grow the buffer to make room for everything
+	offset := dst.Len()
+	dst.Grow(encryptedLength(vsn, len(msg)))
+
+	// Write the encryption version
+	dst.WriteByte(byte(vsn))
+
+	// Add a random nonce
+	io.CopyN(dst, rand.Reader, nonceSize)
+	afterNonce := dst.Len()
+
+	// Ensure we are correctly padded (only version 0)
+	if vsn == 0 {
+		io.Copy(dst, bytes.NewReader(msg))
+		pkcs7encode(dst, offset+versionSize+nonceSize, aes.BlockSize)
+	}
+
+	// Encrypt message using GCM
+	slice := dst.Bytes()[offset:]
+	nonce := slice[versionSize : versionSize+nonceSize]
+
+	// Message source depends on the encryption version.
+	// Version 0 uses padding, version 1 does not
+	var src []byte
+	if vsn == 0 {
+		src = slice[versionSize+nonceSize:]
+	} else {
+		src = msg
+	}
+	out := gcm.Seal(nil, nonce, src, data)
+
+	// Truncate the plaintext, and write the cipher text
+	dst.Truncate(afterNonce)
+	dst.Write(out)
+	return nil
+}
+
+// decryptMessage performs the actual decryption of ciphertext. This is in its
+// own function to allow it to be called on all keys easily.
+func decryptMessage(key, msg []byte, data []byte) ([]byte, error) {
+	// Get the AES block cipher
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get the GCM cipher mode
+	gcm, err := cipher.NewGCM(aesBlock)
+	if err != nil {
+		return nil, err
+	}
+
+	// Decrypt the message
+	nonce := msg[versionSize : versionSize+nonceSize]
+	ciphertext := msg[versionSize+nonceSize:]
+	plain, err := gcm.Open(nil, nonce, ciphertext, data)
+	if err != nil {
+		return nil, err
+	}
+
+	// Success!
+	return plain, nil
+}
+
+// decryptPayload is used to decrypt a message with a given key,
+// and verify it's contents. Any padding will be removed, and a
+// slice to the plaintext is returned. Decryption is done IN PLACE!
+func decryptPayload(keys [][]byte, msg []byte, data []byte) ([]byte, error) {
+	// Ensure we have at least one byte
+	if len(msg) == 0 {
+		return nil, fmt.Errorf("Cannot decrypt empty payload")
+	}
+
+	// Verify the version
+	vsn := encryptionVersion(msg[0])
+	if vsn > maxEncryptionVersion {
+		return nil, fmt.Errorf("Unsupported encryption version %d", msg[0])
+	}
+
+	// Ensure the length is sane
+	if len(msg) < encryptedLength(vsn, 0) {
+		return nil, fmt.Errorf("Payload is too small to decrypt: %d", len(msg))
+	}
+
+	for _, key := range keys {
+		plain, err := decryptMessage(key, msg, data)
+		if err == nil {
+			// Remove the PKCS7 padding for vsn 0
+			if vsn == 0 {
+				return pkcs7decode(plain, aes.BlockSize), nil
+			} else {
+				return plain, nil
+			}
+		}
+	}
+
+	return nil, fmt.Errorf("No installed keys could decrypt the message")
+}

+ 70 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/security_test.go

@@ -0,0 +1,70 @@
+package memberlist
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+)
+
+func TestPKCS7(t *testing.T) {
+	for i := 0; i <= 255; i++ {
+		// Make a buffer of size i
+		buf := []byte{}
+		for j := 0; j < i; j++ {
+			buf = append(buf, byte(i))
+		}
+
+		// Copy to bytes buffer
+		inp := bytes.NewBuffer(nil)
+		inp.Write(buf)
+
+		// Pad this out
+		pkcs7encode(inp, 0, 16)
+
+		// Unpad
+		dec := pkcs7decode(inp.Bytes(), 16)
+
+		// Ensure equivilence
+		if !reflect.DeepEqual(buf, dec) {
+			t.Fatalf("mismatch: %v %v", buf, dec)
+		}
+	}
+
+}
+
+func TestEncryptDecrypt_V0(t *testing.T) {
+	encryptDecryptVersioned(0, t)
+}
+
+func TestEncryptDecrypt_V1(t *testing.T) {
+	encryptDecryptVersioned(1, t)
+}
+
+func encryptDecryptVersioned(vsn encryptionVersion, t *testing.T) {
+	k1 := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+	plaintext := []byte("this is a plain text message")
+	extra := []byte("random data")
+
+	var buf bytes.Buffer
+	err := encryptPayload(vsn, k1, plaintext, extra, &buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	expLen := encryptedLength(vsn, len(plaintext))
+	if buf.Len() != expLen {
+		t.Fatalf("output length is unexpected %d %d %d", len(plaintext), buf.Len(), expLen)
+	}
+
+	msg, err := decryptPayload([][]byte{k1}, buf.Bytes(), extra)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	cmp := bytes.Compare(msg, plaintext)
+	if cmp != 0 {
+		t.Errorf("len %d %v", len(msg), msg)
+		t.Errorf("len %d %v", len(plaintext), plaintext)
+		t.Fatalf("encrypt/decrypt failed! %d '%s' '%s'", cmp, msg, plaintext)
+	}
+}

+ 916 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/state.go

@@ -0,0 +1,916 @@
+package memberlist
+
+import (
+	"bytes"
+	"fmt"
+	"math"
+	"math/rand"
+	"net"
+	"sync/atomic"
+	"time"
+
+	"github.com/armon/go-metrics"
+)
+
+type nodeStateType int
+
+const (
+	stateAlive nodeStateType = iota
+	stateSuspect
+	stateDead
+)
+
+// Node represents a node in the cluster.
+type Node struct {
+	Name string
+	Addr net.IP
+	Port uint16
+	Meta []byte // Metadata from the delegate for this node.
+	PMin uint8  // Minimum protocol version this understands
+	PMax uint8  // Maximum protocol version this understands
+	PCur uint8  // Current version node is speaking
+	DMin uint8  // Min protocol version for the delegate to understand
+	DMax uint8  // Max protocol version for the delegate to understand
+	DCur uint8  // Current version delegate is speaking
+}
+
+// NodeState is used to manage our state view of another node
+type nodeState struct {
+	Node
+	Incarnation uint32        // Last known incarnation number
+	State       nodeStateType // Current state
+	StateChange time.Time     // Time last state change happened
+}
+
+// ackHandler is used to register handlers for incoming acks
+type ackHandler struct {
+	handler func()
+	timer   *time.Timer
+}
+
+// Schedule is used to ensure the Tick is performed periodically. This
+// function is safe to call multiple times. If the memberlist is already
+// scheduled, then it won't do anything.
+func (m *Memberlist) schedule() {
+	m.tickerLock.Lock()
+	defer m.tickerLock.Unlock()
+
+	// If we already have tickers, then don't do anything, since we're
+	// scheduled
+	if len(m.tickers) > 0 {
+		return
+	}
+
+	// Create the stop tick channel, a blocking channel. We close this
+	// when we should stop the tickers.
+	stopCh := make(chan struct{})
+
+	// Create a new probeTicker
+	if m.config.ProbeInterval > 0 {
+		t := time.NewTicker(m.config.ProbeInterval)
+		go m.triggerFunc(m.config.ProbeInterval, t.C, stopCh, m.probe)
+		m.tickers = append(m.tickers, t)
+	}
+
+	// Create a push pull ticker if needed
+	if m.config.PushPullInterval > 0 {
+		go m.pushPullTrigger(stopCh)
+	}
+
+	// Create a gossip ticker if needed
+	if m.config.GossipInterval > 0 && m.config.GossipNodes > 0 {
+		t := time.NewTicker(m.config.GossipInterval)
+		go m.triggerFunc(m.config.GossipInterval, t.C, stopCh, m.gossip)
+		m.tickers = append(m.tickers, t)
+	}
+
+	// If we made any tickers, then record the stopTick channel for
+	// later.
+	if len(m.tickers) > 0 {
+		m.stopTick = stopCh
+	}
+}
+
+// triggerFunc is used to trigger a function call each time a
+// message is received until a stop tick arrives.
+func (m *Memberlist) triggerFunc(stagger time.Duration, C <-chan time.Time, stop <-chan struct{}, f func()) {
+	// Use a random stagger to avoid syncronizing
+	randStagger := time.Duration(uint64(rand.Int63()) % uint64(stagger))
+	select {
+	case <-time.After(randStagger):
+	case <-stop:
+		return
+	}
+	for {
+		select {
+		case <-C:
+			f()
+		case <-stop:
+			return
+		}
+	}
+}
+
+// pushPullTrigger is used to periodically trigger a push/pull until
+// a stop tick arrives. We don't use triggerFunc since the push/pull
+// timer is dynamically scaled based on cluster size to avoid network
+// saturation
+func (m *Memberlist) pushPullTrigger(stop <-chan struct{}) {
+	interval := m.config.PushPullInterval
+
+	// Use a random stagger to avoid syncronizing
+	randStagger := time.Duration(uint64(rand.Int63()) % uint64(interval))
+	select {
+	case <-time.After(randStagger):
+	case <-stop:
+		return
+	}
+
+	// Tick using a dynamic timer
+	for {
+		m.nodeLock.RLock()
+		tickTime := pushPullScale(interval, len(m.nodes))
+		m.nodeLock.RUnlock()
+		select {
+		case <-time.After(tickTime):
+			m.pushPull()
+		case <-stop:
+			return
+		}
+	}
+}
+
+// Deschedule is used to stop the background maintenence. This is safe
+// to call multiple times.
+func (m *Memberlist) deschedule() {
+	m.tickerLock.Lock()
+	defer m.tickerLock.Unlock()
+
+	// If we have no tickers, then we aren't scheduled.
+	if len(m.tickers) == 0 {
+		return
+	}
+
+	// Close the stop channel so all the ticker listeners stop.
+	close(m.stopTick)
+
+	// Explicitly stop all the tickers themselves so they don't take
+	// up any more resources, and get rid of the list.
+	for _, t := range m.tickers {
+		t.Stop()
+	}
+	m.tickers = nil
+}
+
+// Tick is used to perform a single round of failure detection and gossip
+func (m *Memberlist) probe() {
+	// Track the number of indexes we've considered probing
+	numCheck := 0
+START:
+	m.nodeLock.RLock()
+
+	// Make sure we don't wrap around infinitely
+	if numCheck >= len(m.nodes) {
+		m.nodeLock.RUnlock()
+		return
+	}
+
+	// Handle the wrap around case
+	if m.probeIndex >= len(m.nodes) {
+		m.nodeLock.RUnlock()
+		m.resetNodes()
+		m.probeIndex = 0
+		numCheck++
+		goto START
+	}
+
+	// Determine if we should probe this node
+	skip := false
+	var node nodeState
+
+	node = *m.nodes[m.probeIndex]
+	if node.Name == m.config.Name {
+		skip = true
+	} else if node.State == stateDead {
+		skip = true
+	}
+
+	// Potentially skip
+	m.nodeLock.RUnlock()
+	m.probeIndex++
+	if skip {
+		numCheck++
+		goto START
+	}
+
+	// Probe the specific node
+	m.probeNode(&node)
+}
+
+// probeNode handles a single round of failure checking on a node
+func (m *Memberlist) probeNode(node *nodeState) {
+	defer metrics.MeasureSince([]string{"memberlist", "probeNode"}, time.Now())
+
+	// Send a ping to the node
+	ping := ping{SeqNo: m.nextSeqNo(), Node: node.Name}
+	destAddr := &net.UDPAddr{IP: node.Addr, Port: int(node.Port)}
+
+	// Setup an ack handler
+	ackCh := make(chan bool, m.config.IndirectChecks+1)
+	m.setAckChannel(ping.SeqNo, ackCh, m.config.ProbeInterval)
+
+	// Send the ping message
+	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
+		m.logger.Printf("[ERR] memberlist: Failed to send ping: %s", err)
+		return
+	}
+
+	// Wait for response or round-trip-time
+	select {
+	case v := <-ackCh:
+		if v == true {
+			return
+		}
+
+		// As an edge case, if we get a timeout, we need to re-enqueue it
+		// here to break out of the select below
+		if v == false {
+			ackCh <- v
+		}
+	case <-time.After(m.config.ProbeTimeout):
+	}
+
+	// Get some random live nodes
+	m.nodeLock.RLock()
+	excludes := []string{m.config.Name, node.Name}
+	kNodes := kRandomNodes(m.config.IndirectChecks, excludes, m.nodes)
+	m.nodeLock.RUnlock()
+
+	// Attempt an indirect ping
+	ind := indirectPingReq{SeqNo: ping.SeqNo, Target: node.Addr, Port: node.Port, Node: node.Name}
+	for _, peer := range kNodes {
+		destAddr := &net.UDPAddr{IP: peer.Addr, Port: int(peer.Port)}
+		if err := m.encodeAndSendMsg(destAddr, indirectPingMsg, &ind); err != nil {
+			m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s", err)
+		}
+	}
+
+	// Wait for the acks or timeout
+	select {
+	case v := <-ackCh:
+		if v == true {
+			return
+		}
+	}
+
+	// No acks received from target, suspect
+	m.logger.Printf("[INFO] memberlist: Suspect %s has failed, no acks received", node.Name)
+	s := suspect{Incarnation: node.Incarnation, Node: node.Name, From: m.config.Name}
+	m.suspectNode(&s)
+}
+
+// resetNodes is used when the tick wraps around. It will reap the
+// dead nodes and shuffle the node list.
+func (m *Memberlist) resetNodes() {
+	m.nodeLock.Lock()
+	defer m.nodeLock.Unlock()
+
+	// Move the dead nodes
+	deadIdx := moveDeadNodes(m.nodes)
+
+	// Deregister the dead nodes
+	for i := deadIdx; i < len(m.nodes); i++ {
+		delete(m.nodeMap, m.nodes[i].Name)
+		m.nodes[i] = nil
+	}
+
+	// Trim the nodes to exclude the dead nodes
+	m.nodes = m.nodes[0:deadIdx]
+
+	// Shuffle live nodes
+	shuffleNodes(m.nodes)
+}
+
+// gossip is invoked every GossipInterval period to broadcast our gossip
+// messages to a few random nodes.
+func (m *Memberlist) gossip() {
+	defer metrics.MeasureSince([]string{"memberlist", "gossip"}, time.Now())
+
+	// Get some random live nodes
+	m.nodeLock.RLock()
+	excludes := []string{m.config.Name}
+	kNodes := kRandomNodes(m.config.GossipNodes, excludes, m.nodes)
+	m.nodeLock.RUnlock()
+
+	// Compute the bytes available
+	bytesAvail := udpSendBuf - compoundHeaderOverhead
+	if m.config.EncryptionEnabled() {
+		bytesAvail -= encryptOverhead(m.encryptionVersion())
+	}
+
+	for _, node := range kNodes {
+		// Get any pending broadcasts
+		msgs := m.getBroadcasts(compoundOverhead, bytesAvail)
+		if len(msgs) == 0 {
+			return
+		}
+
+		// Create a compound message
+		compound := makeCompoundMessage(msgs)
+
+		// Send the compound message
+		destAddr := &net.UDPAddr{IP: node.Addr, Port: int(node.Port)}
+		if err := m.rawSendMsg(destAddr, compound.Bytes()); err != nil {
+			m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", destAddr, err)
+		}
+	}
+}
+
+// pushPull is invoked periodically to randomly perform a complete state
+// exchange. Used to ensure a high level of convergence, but is also
+// reasonably expensive as the entire state of this node is exchanged
+// with the other node.
+func (m *Memberlist) pushPull() {
+	// Get a random live node
+	m.nodeLock.RLock()
+	excludes := []string{m.config.Name}
+	nodes := kRandomNodes(1, excludes, m.nodes)
+	m.nodeLock.RUnlock()
+
+	// If no nodes, bail
+	if len(nodes) == 0 {
+		return
+	}
+	node := nodes[0]
+
+	// Attempt a push pull
+	if err := m.pushPullNode(node.Addr, node.Port, false); err != nil {
+		m.logger.Printf("[ERR] memberlist: Push/Pull with %s failed: %s", node.Name, err)
+	}
+}
+
+// pushPullNode does a complete state exchange with a specific node.
+func (m *Memberlist) pushPullNode(addr []byte, port uint16, join bool) error {
+	defer metrics.MeasureSince([]string{"memberlist", "pushPullNode"}, time.Now())
+
+	// Attempt to send and receive with the node
+	remote, userState, err := m.sendAndReceiveState(addr, port, join)
+	if err != nil {
+		return err
+	}
+
+	if err := m.verifyProtocol(remote); err != nil {
+		return err
+	}
+
+	// Invoke the merge delegate if any
+	if join && m.config.Merge != nil {
+		nodes := make([]*Node, len(remote))
+		for idx, n := range remote {
+			nodes[idx] = &Node{
+				Name: n.Name,
+				Addr: n.Addr,
+				Port: n.Port,
+				Meta: n.Meta,
+				PMin: n.Vsn[0],
+				PMax: n.Vsn[1],
+				PCur: n.Vsn[2],
+				DMin: n.Vsn[3],
+				DMax: n.Vsn[4],
+				DCur: n.Vsn[5],
+			}
+		}
+		if m.config.Merge.NotifyMerge(nodes) {
+			m.logger.Printf("[WARN] memberlist: Cluster merge canceled")
+			return fmt.Errorf("Merge canceled")
+		}
+	}
+
+	// Merge the state
+	m.mergeState(remote)
+
+	// Invoke the delegate
+	if m.config.Delegate != nil {
+		m.config.Delegate.MergeRemoteState(userState, join)
+	}
+	return nil
+}
+
+// verifyProtocol verifies that all the remote nodes can speak with our
+// nodes and vice versa on both the core protocol as well as the
+// delegate protocol level.
+//
+// The verification works by finding the maximum minimum and
+// minimum maximum understood protocol and delegate versions. In other words,
+// it finds the common denominator of protocol and delegate version ranges
+// for the entire cluster.
+//
+// After this, it goes through the entire cluster (local and remote) and
+// verifies that everyone's speaking protocol versions satisfy this range.
+// If this passes, it means that every node can understand each other.
+func (m *Memberlist) verifyProtocol(remote []pushNodeState) error {
+	m.nodeLock.RLock()
+	defer m.nodeLock.RUnlock()
+
+	// Maximum minimum understood and minimum maximum understood for both
+	// the protocol and delegate versions. We use this to verify everyone
+	// can be understood.
+	var maxpmin, minpmax uint8
+	var maxdmin, mindmax uint8
+	minpmax = math.MaxUint8
+	mindmax = math.MaxUint8
+
+	for _, rn := range remote {
+		// If the node isn't alive, then skip it
+		if rn.State != stateAlive {
+			continue
+		}
+
+		// Skip nodes that don't have versions set, it just means
+		// their version is zero.
+		if len(rn.Vsn) == 0 {
+			continue
+		}
+
+		if rn.Vsn[0] > maxpmin {
+			maxpmin = rn.Vsn[0]
+		}
+
+		if rn.Vsn[1] < minpmax {
+			minpmax = rn.Vsn[1]
+		}
+
+		if rn.Vsn[3] > maxdmin {
+			maxdmin = rn.Vsn[3]
+		}
+
+		if rn.Vsn[4] < mindmax {
+			mindmax = rn.Vsn[4]
+		}
+	}
+
+	for _, n := range m.nodes {
+		// Ignore non-alive nodes
+		if n.State != stateAlive {
+			continue
+		}
+
+		if n.PMin > maxpmin {
+			maxpmin = n.PMin
+		}
+
+		if n.PMax < minpmax {
+			minpmax = n.PMax
+		}
+
+		if n.DMin > maxdmin {
+			maxdmin = n.DMin
+		}
+
+		if n.DMax < mindmax {
+			mindmax = n.DMax
+		}
+	}
+
+	// Now that we definitively know the minimum and maximum understood
+	// version that satisfies the whole cluster, we verify that every
+	// node in the cluster satisifies this.
+	for _, n := range remote {
+		var nPCur, nDCur uint8
+		if len(n.Vsn) > 0 {
+			nPCur = n.Vsn[2]
+			nDCur = n.Vsn[5]
+		}
+
+		if nPCur < maxpmin || nPCur > minpmax {
+			return fmt.Errorf(
+				"Node '%s' protocol version (%d) is incompatible: [%d, %d]",
+				n.Name, nPCur, maxpmin, minpmax)
+		}
+
+		if nDCur < maxdmin || nDCur > mindmax {
+			return fmt.Errorf(
+				"Node '%s' delegate protocol version (%d) is incompatible: [%d, %d]",
+				n.Name, nDCur, maxdmin, mindmax)
+		}
+	}
+
+	for _, n := range m.nodes {
+		nPCur := n.PCur
+		nDCur := n.DCur
+
+		if nPCur < maxpmin || nPCur > minpmax {
+			return fmt.Errorf(
+				"Node '%s' protocol version (%d) is incompatible: [%d, %d]",
+				n.Name, nPCur, maxpmin, minpmax)
+		}
+
+		if nDCur < maxdmin || nDCur > mindmax {
+			return fmt.Errorf(
+				"Node '%s' delegate protocol version (%d) is incompatible: [%d, %d]",
+				n.Name, nDCur, maxdmin, mindmax)
+		}
+	}
+
+	return nil
+}
+
+// nextSeqNo returns a usable sequence number in a thread safe way
+func (m *Memberlist) nextSeqNo() uint32 {
+	return atomic.AddUint32(&m.sequenceNum, 1)
+}
+
+// nextIncarnation returns the next incarnation number in a thread safe way
+func (m *Memberlist) nextIncarnation() uint32 {
+	return atomic.AddUint32(&m.incarnation, 1)
+}
+
+// setAckChannel is used to attach a channel to receive a message when
+// an ack with a given sequence number is received. The channel gets sent
+// false on timeout
+func (m *Memberlist) setAckChannel(seqNo uint32, ch chan bool, timeout time.Duration) {
+	// Create a handler function
+	handler := func() {
+		select {
+		case ch <- true:
+		default:
+		}
+	}
+
+	// Add the handler
+	ah := &ackHandler{handler, nil}
+	m.ackLock.Lock()
+	m.ackHandlers[seqNo] = ah
+	m.ackLock.Unlock()
+
+	// Setup a reaping routing
+	ah.timer = time.AfterFunc(timeout, func() {
+		m.ackLock.Lock()
+		delete(m.ackHandlers, seqNo)
+		m.ackLock.Unlock()
+		select {
+		case ch <- false:
+		default:
+		}
+	})
+}
+
+// setAckHandler is used to attach a handler to be invoked when an
+// ack with a given sequence number is received. If a timeout is reached,
+// the handler is deleted
+func (m *Memberlist) setAckHandler(seqNo uint32, handler func(), timeout time.Duration) {
+	// Add the handler
+	ah := &ackHandler{handler, nil}
+	m.ackLock.Lock()
+	m.ackHandlers[seqNo] = ah
+	m.ackLock.Unlock()
+
+	// Setup a reaping routing
+	ah.timer = time.AfterFunc(timeout, func() {
+		m.ackLock.Lock()
+		delete(m.ackHandlers, seqNo)
+		m.ackLock.Unlock()
+	})
+}
+
+// Invokes an Ack handler if any is associated, and reaps the handler immediately
+func (m *Memberlist) invokeAckHandler(seqNo uint32) {
+	m.ackLock.Lock()
+	ah, ok := m.ackHandlers[seqNo]
+	delete(m.ackHandlers, seqNo)
+	m.ackLock.Unlock()
+	if !ok {
+		return
+	}
+	ah.timer.Stop()
+	ah.handler()
+}
+
+// aliveNode is invoked by the network layer when we get a message about a
+// live node.
+func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) {
+	m.nodeLock.Lock()
+	defer m.nodeLock.Unlock()
+	state, ok := m.nodeMap[a.Node]
+
+	// It is possible that during a Leave(), there is already an aliveMsg
+	// in-queue to be processed but blocked by the locks above. If we let
+	// that aliveMsg process, it'll cause us to re-join the cluster. This
+	// ensures that we don't.
+	if m.leave && a.Node == m.config.Name {
+		return
+	}
+
+	// Check if we've never seen this node before, and if not, then
+	// store this node in our node map.
+	if !ok {
+		state = &nodeState{
+			Node: Node{
+				Name: a.Node,
+				Addr: a.Addr,
+				Port: a.Port,
+				Meta: a.Meta,
+			},
+			State: stateDead,
+		}
+
+		// Add to map
+		m.nodeMap[a.Node] = state
+
+		// Get a random offset. This is important to ensure
+		// the failure detection bound is low on average. If all
+		// nodes did an append, failure detection bound would be
+		// very high.
+		n := len(m.nodes)
+		offset := randomOffset(n)
+
+		// Add at the end and swap with the node at the offset
+		m.nodes = append(m.nodes, state)
+		m.nodes[offset], m.nodes[n] = m.nodes[n], m.nodes[offset]
+	}
+
+	// Check if this address is different than the existing node
+	if !bytes.Equal([]byte(state.Addr), a.Addr) || state.Port != a.Port {
+		m.logger.Printf("[ERR] memberlist: Conflicting address for %s. Mine: %v:%d Theirs: %v:%d",
+			state.Name, state.Addr, state.Port, net.IP(a.Addr), a.Port)
+
+		// Inform the conflict delegate if provided
+		if m.config.Conflict != nil {
+			other := Node{
+				Name: a.Node,
+				Addr: a.Addr,
+				Port: a.Port,
+				Meta: a.Meta,
+			}
+			m.config.Conflict.NotifyConflict(&state.Node, &other)
+		}
+		return
+	}
+
+	// Bail if the incarnation number is older, and this is not about us
+	isLocalNode := state.Name == m.config.Name
+	if a.Incarnation <= state.Incarnation && !isLocalNode {
+		return
+	}
+
+	// Bail if strictly less and this is about us
+	if a.Incarnation < state.Incarnation && isLocalNode {
+		return
+	}
+
+	// Update metrics
+	metrics.IncrCounter([]string{"memberlist", "msg", "alive"}, 1)
+
+	// Store the old state and meta data
+	oldState := state.State
+	oldMeta := state.Meta
+
+	// If this is us we need to refute, otherwise re-broadcast
+	if !bootstrap && isLocalNode {
+		// Compute the version vector
+		versions := []uint8{
+			state.PMin, state.PMax, state.PCur,
+			state.DMin, state.DMax, state.DCur,
+		}
+
+		// If the Incarnation is the same, we need special handling, since it
+		// possible for the following situation to happen:
+		// 1) Start with configuration C, join cluster
+		// 2) Hard fail / Kill / Shutdown
+		// 3) Restart with configuration C', join cluster
+		//
+		// In this case, other nodes and the local node see the same incarnation,
+		// but the values may not be the same. For this reason, we always
+		// need to do an equality check for this Incarnation. In most cases,
+		// we just ignore, but we may need to refute.
+		//
+		if a.Incarnation == state.Incarnation &&
+			bytes.Equal(a.Meta, state.Meta) &&
+			bytes.Equal(a.Vsn, versions) {
+			return
+		}
+
+		inc := m.nextIncarnation()
+		for a.Incarnation >= inc {
+			inc = m.nextIncarnation()
+		}
+		state.Incarnation = inc
+
+		a := alive{
+			Incarnation: inc,
+			Node:        state.Name,
+			Addr:        state.Addr,
+			Port:        state.Port,
+			Meta:        state.Meta,
+			Vsn:         versions,
+		}
+		m.encodeBroadcastNotify(a.Node, aliveMsg, a, notify)
+		m.logger.Printf("[WARN] memberlist: Refuting an alive message")
+	} else {
+		m.encodeBroadcastNotify(a.Node, aliveMsg, a, notify)
+
+		// Update protocol versions if it arrived
+		if len(a.Vsn) > 0 {
+			state.PMin = a.Vsn[0]
+			state.PMax = a.Vsn[1]
+			state.PCur = a.Vsn[2]
+			state.DMin = a.Vsn[3]
+			state.DMax = a.Vsn[4]
+			state.DCur = a.Vsn[5]
+		}
+
+		// Update the state and incarnation number
+		state.Incarnation = a.Incarnation
+		state.Meta = a.Meta
+		if state.State != stateAlive {
+			state.State = stateAlive
+			state.StateChange = time.Now()
+		}
+	}
+
+	// Notify the delegate of any relevant updates
+	if m.config.Events != nil {
+		if oldState == stateDead {
+			// if Dead -> Alive, notify of join
+			m.config.Events.NotifyJoin(&state.Node)
+
+		} else if !bytes.Equal(oldMeta, state.Meta) {
+			// if Meta changed, trigger an update notification
+			m.config.Events.NotifyUpdate(&state.Node)
+		}
+	}
+}
+
+// suspectNode is invoked by the network layer when we get a message
+// about a suspect node
+func (m *Memberlist) suspectNode(s *suspect) {
+	m.nodeLock.Lock()
+	defer m.nodeLock.Unlock()
+	state, ok := m.nodeMap[s.Node]
+
+	// If we've never heard about this node before, ignore it
+	if !ok {
+		return
+	}
+
+	// Ignore old incarnation numbers
+	if s.Incarnation < state.Incarnation {
+		return
+	}
+
+	// Ignore non-alive nodes
+	if state.State != stateAlive {
+		return
+	}
+
+	// If this is us we need to refute, otherwise re-broadcast
+	if state.Name == m.config.Name {
+		inc := m.nextIncarnation()
+		for s.Incarnation >= inc {
+			inc = m.nextIncarnation()
+		}
+		state.Incarnation = inc
+
+		a := alive{
+			Incarnation: inc,
+			Node:        state.Name,
+			Addr:        state.Addr,
+			Port:        state.Port,
+			Meta:        state.Meta,
+			Vsn: []uint8{
+				state.PMin, state.PMax, state.PCur,
+				state.DMin, state.DMax, state.DCur,
+			},
+		}
+		m.encodeAndBroadcast(s.Node, aliveMsg, a)
+		m.logger.Printf("[WARN] memberlist: Refuting a suspect message (from: %s)", s.From)
+		return // Do not mark ourself suspect
+	} else {
+		m.encodeAndBroadcast(s.Node, suspectMsg, s)
+	}
+
+	// Update metrics
+	metrics.IncrCounter([]string{"memberlist", "msg", "suspect"}, 1)
+
+	// Update the state
+	state.Incarnation = s.Incarnation
+	state.State = stateSuspect
+	changeTime := time.Now()
+	state.StateChange = changeTime
+
+	// Setup a timeout for this
+	timeout := suspicionTimeout(m.config.SuspicionMult, len(m.nodes), m.config.ProbeInterval)
+	time.AfterFunc(timeout, func() {
+		m.nodeLock.Lock()
+		state, ok := m.nodeMap[s.Node]
+		timeout := ok && state.State == stateSuspect && state.StateChange == changeTime
+		m.nodeLock.Unlock()
+
+		if timeout {
+			m.suspectTimeout(state)
+		}
+	})
+}
+
+// suspectTimeout is invoked when a suspect timeout has occurred
+func (m *Memberlist) suspectTimeout(n *nodeState) {
+	// Construct a dead message
+	m.logger.Printf("[INFO] memberlist: Marking %s as failed, suspect timeout reached", n.Name)
+	d := dead{Incarnation: n.Incarnation, Node: n.Name, From: m.config.Name}
+	m.deadNode(&d)
+}
+
+// deadNode is invoked by the network layer when we get a message
+// about a dead node
+func (m *Memberlist) deadNode(d *dead) {
+	m.nodeLock.Lock()
+	defer m.nodeLock.Unlock()
+	state, ok := m.nodeMap[d.Node]
+
+	// If we've never heard about this node before, ignore it
+	if !ok {
+		return
+	}
+
+	// Ignore old incarnation numbers
+	if d.Incarnation < state.Incarnation {
+		return
+	}
+
+	// Ignore if node is already dead
+	if state.State == stateDead {
+		return
+	}
+
+	// Check if this is us
+	if state.Name == m.config.Name {
+		// If we are not leaving we need to refute
+		if !m.leave {
+			inc := m.nextIncarnation()
+			for d.Incarnation >= inc {
+				inc = m.nextIncarnation()
+			}
+			state.Incarnation = inc
+
+			a := alive{
+				Incarnation: inc,
+				Node:        state.Name,
+				Addr:        state.Addr,
+				Port:        state.Port,
+				Meta:        state.Meta,
+				Vsn: []uint8{
+					state.PMin, state.PMax, state.PCur,
+					state.DMin, state.DMax, state.DCur,
+				},
+			}
+			m.encodeAndBroadcast(d.Node, aliveMsg, a)
+			m.logger.Printf("[WARN] memberlist: Refuting a dead message (from: %s)", d.From)
+			return // Do not mark ourself dead
+		}
+
+		// If we are leaving, we broadcast and wait
+		m.encodeBroadcastNotify(d.Node, deadMsg, d, m.leaveBroadcast)
+	} else {
+		m.encodeAndBroadcast(d.Node, deadMsg, d)
+	}
+
+	// Update metrics
+	metrics.IncrCounter([]string{"memberlist", "msg", "dead"}, 1)
+
+	// Update the state
+	state.Incarnation = d.Incarnation
+	state.State = stateDead
+	state.StateChange = time.Now()
+
+	// Notify of death
+	if m.config.Events != nil {
+		m.config.Events.NotifyLeave(&state.Node)
+	}
+}
+
+// mergeState is invoked by the network layer when we get a Push/Pull
+// state transfer
+func (m *Memberlist) mergeState(remote []pushNodeState) {
+	for _, r := range remote {
+		switch r.State {
+		case stateAlive:
+			a := alive{
+				Incarnation: r.Incarnation,
+				Node:        r.Name,
+				Addr:        r.Addr,
+				Port:        r.Port,
+				Meta:        r.Meta,
+				Vsn:         r.Vsn,
+			}
+			m.aliveNode(&a, nil, false)
+
+		case stateDead:
+			// If the remote node belives a node is dead, we prefer to
+			// suspect that node instead of declaring it dead instantly
+			fallthrough
+		case stateSuspect:
+			s := suspect{Incarnation: r.Incarnation, Node: r.Name, From: m.config.Name}
+			m.suspectNode(&s)
+		}
+	}
+}

+ 1039 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/state_test.go

@@ -0,0 +1,1039 @@
+package memberlist
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+	"time"
+)
+
+func HostMemberlist(host string, t *testing.T, f func(*Config)) *Memberlist {
+	c := DefaultLANConfig()
+	c.Name = host
+	c.BindAddr = host
+	if f != nil {
+		f(c)
+	}
+
+	m, err := newMemberlist(c)
+	if err != nil {
+		t.Fatalf("failed to get memberlist: %s", err)
+	}
+	return m
+}
+
+func TestMemberList_Probe(t *testing.T) {
+	addr1 := getBindAddr()
+	addr2 := getBindAddr()
+	m1 := HostMemberlist(addr1.String(), t, func(c *Config) {
+		c.ProbeTimeout = time.Millisecond
+		c.ProbeInterval = 10 * time.Millisecond
+	})
+	m2 := HostMemberlist(addr2.String(), t, nil)
+
+	a1 := alive{
+		Node:        addr1.String(),
+		Addr:        []byte(addr1),
+		Port:        uint16(m1.config.BindPort),
+		Incarnation: 1,
+	}
+	m1.aliveNode(&a1, nil, true)
+	a2 := alive{
+		Node:        addr2.String(),
+		Addr:        []byte(addr2),
+		Port:        uint16(m2.config.BindPort),
+		Incarnation: 1,
+	}
+	m1.aliveNode(&a2, nil, false)
+
+	// should ping addr2
+	m1.probe()
+
+	// Should not be marked suspect
+	n := m1.nodeMap[addr2.String()]
+	if n.State != stateAlive {
+		t.Fatalf("Expect node to be alive")
+	}
+
+	// Should increment seqno
+	if m1.sequenceNum != 1 {
+		t.Fatalf("bad seqno %v", m2.sequenceNum)
+	}
+}
+
+func TestMemberList_ProbeNode_Suspect(t *testing.T) {
+	addr1 := getBindAddr()
+	addr2 := getBindAddr()
+	addr3 := getBindAddr()
+	addr4 := getBindAddr()
+	ip1 := []byte(addr1)
+	ip2 := []byte(addr2)
+	ip3 := []byte(addr3)
+	ip4 := []byte(addr4)
+
+	m1 := HostMemberlist(addr1.String(), t, func(c *Config) {
+		c.ProbeTimeout = time.Millisecond
+		c.ProbeInterval = 10 * time.Millisecond
+	})
+	m2 := HostMemberlist(addr2.String(), t, nil)
+	m3 := HostMemberlist(addr3.String(), t, nil)
+
+	a1 := alive{Node: addr1.String(), Addr: ip1, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a1, nil, true)
+	a2 := alive{Node: addr2.String(), Addr: ip2, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a2, nil, false)
+	a3 := alive{Node: addr3.String(), Addr: ip3, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a3, nil, false)
+	a4 := alive{Node: addr4.String(), Addr: ip4, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a4, nil, false)
+
+	n := m1.nodeMap[addr4.String()]
+	m1.probeNode(n)
+
+	// Should be marked suspect
+	if n.State != stateSuspect {
+		t.Fatalf("Expect node to be suspect")
+	}
+	time.Sleep(10 * time.Millisecond)
+
+	// Should increment seqno
+	if m2.sequenceNum != 1 {
+		t.Fatalf("bad seqno %v", m2.sequenceNum)
+	}
+	if m3.sequenceNum != 1 {
+		t.Fatalf("bad seqno %v", m3.sequenceNum)
+	}
+}
+
+func TestMemberList_ProbeNode(t *testing.T) {
+	addr1 := getBindAddr()
+	addr2 := getBindAddr()
+	ip1 := []byte(addr1)
+	ip2 := []byte(addr2)
+
+	m1 := HostMemberlist(addr1.String(), t, func(c *Config) {
+		c.ProbeTimeout = time.Millisecond
+		c.ProbeInterval = 10 * time.Millisecond
+	})
+	m2 := HostMemberlist(addr2.String(), t, nil)
+
+	a1 := alive{Node: addr1.String(), Addr: ip1, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a1, nil, true)
+	a2 := alive{Node: addr2.String(), Addr: ip2, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a2, nil, false)
+
+	n := m1.nodeMap[addr2.String()]
+	m1.probeNode(n)
+
+	// Should be marked suspect
+	if n.State != stateAlive {
+		t.Fatalf("Expect node to be alive")
+	}
+
+	// Should increment seqno
+	if m1.sequenceNum != 1 {
+		t.Fatalf("bad seqno %v", m2.sequenceNum)
+	}
+}
+
+func TestMemberList_ResetNodes(t *testing.T) {
+	m := GetMemberlist(t)
+	a1 := alive{Node: "test1", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a1, nil, false)
+	a2 := alive{Node: "test2", Addr: []byte{127, 0, 0, 2}, Incarnation: 1}
+	m.aliveNode(&a2, nil, false)
+	a3 := alive{Node: "test3", Addr: []byte{127, 0, 0, 3}, Incarnation: 1}
+	m.aliveNode(&a3, nil, false)
+	d := dead{Node: "test2", Incarnation: 1}
+	m.deadNode(&d)
+
+	m.resetNodes()
+	if len(m.nodes) != 2 {
+		t.Fatalf("Bad length")
+	}
+	if _, ok := m.nodeMap["test2"]; ok {
+		t.Fatalf("test2 should be unmapped")
+	}
+}
+
+func TestMemberList_NextSeq(t *testing.T) {
+	m := &Memberlist{}
+	if m.nextSeqNo() != 1 {
+		t.Fatalf("bad sequence no")
+	}
+	if m.nextSeqNo() != 2 {
+		t.Fatalf("bad sequence no")
+	}
+}
+
+func TestMemberList_SetAckChannel(t *testing.T) {
+	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}
+
+	ch := make(chan bool, 1)
+	m.setAckChannel(0, ch, 10*time.Millisecond)
+
+	if _, ok := m.ackHandlers[0]; !ok {
+		t.Fatalf("missing handler")
+	}
+	time.Sleep(11 * time.Millisecond)
+
+	if _, ok := m.ackHandlers[0]; ok {
+		t.Fatalf("non-reaped handler")
+	}
+}
+
+func TestMemberList_SetAckHandler(t *testing.T) {
+	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}
+
+	f := func() {}
+	m.setAckHandler(0, f, 10*time.Millisecond)
+
+	if _, ok := m.ackHandlers[0]; !ok {
+		t.Fatalf("missing handler")
+	}
+	time.Sleep(11 * time.Millisecond)
+
+	if _, ok := m.ackHandlers[0]; ok {
+		t.Fatalf("non-reaped handler")
+	}
+}
+
+func TestMemberList_InvokeAckHandler(t *testing.T) {
+	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}
+
+	// Does nothing
+	m.invokeAckHandler(0)
+
+	var b bool
+	f := func() { b = true }
+	m.setAckHandler(0, f, 10*time.Millisecond)
+
+	// Should set b
+	m.invokeAckHandler(0)
+	if !b {
+		t.Fatalf("b not set")
+	}
+
+	if _, ok := m.ackHandlers[0]; ok {
+		t.Fatalf("non-reaped handler")
+	}
+}
+
+func TestMemberList_InvokeAckHandler_Channel(t *testing.T) {
+	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}
+
+	// Does nothing
+	m.invokeAckHandler(0)
+
+	ch := make(chan bool, 1)
+	m.setAckChannel(0, ch, 10*time.Millisecond)
+
+	// Should send message
+	m.invokeAckHandler(0)
+
+	select {
+	case v := <-ch:
+		if v != true {
+			t.Fatalf("Bad value")
+		}
+	default:
+		t.Fatalf("message not sent")
+	}
+
+	if _, ok := m.ackHandlers[0]; ok {
+		t.Fatalf("non-reaped handler")
+	}
+}
+
+func TestMemberList_AliveNode_NewNode(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+	m.config.Events = &ChannelEventDelegate{ch}
+
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	if len(m.nodes) != 1 {
+		t.Fatalf("should add node")
+	}
+
+	state, ok := m.nodeMap["test"]
+	if !ok {
+		t.Fatalf("should map node")
+	}
+
+	if state.Incarnation != 1 {
+		t.Fatalf("bad incarnation")
+	}
+	if state.State != stateAlive {
+		t.Fatalf("bad state")
+	}
+	if time.Now().Sub(state.StateChange) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+
+	// Check for a join message
+	select {
+	case e := <-ch:
+		if e.Node.Name != "test" {
+			t.Fatalf("bad node name")
+		}
+	default:
+		t.Fatalf("no join message")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected queued message")
+	}
+}
+
+func TestMemberList_AliveNode_SuspectNode(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	// Listen only after first join
+	m.config.Events = &ChannelEventDelegate{ch}
+
+	// Make suspect
+	state := m.nodeMap["test"]
+	state.State = stateSuspect
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	// Old incarnation number, should not change
+	m.aliveNode(&a, nil, false)
+	if state.State != stateSuspect {
+		t.Fatalf("update with old incarnation!")
+	}
+
+	// Should reset to alive now
+	a.Incarnation = 2
+	m.aliveNode(&a, nil, false)
+	if state.State != stateAlive {
+		t.Fatalf("no update with new incarnation!")
+	}
+
+	if time.Now().Sub(state.StateChange) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+
+	// Check for a no join message
+	select {
+	case <-ch:
+		t.Fatalf("got bad join message")
+	default:
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected queued message")
+	}
+}
+
+func TestMemberList_AliveNode_Idempotent(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	// Listen only after first join
+	m.config.Events = &ChannelEventDelegate{ch}
+
+	// Make suspect
+	state := m.nodeMap["test"]
+	stateTime := state.StateChange
+
+	// Should reset to alive now
+	a.Incarnation = 2
+	m.aliveNode(&a, nil, false)
+	if state.State != stateAlive {
+		t.Fatalf("non idempotent")
+	}
+
+	if stateTime != state.StateChange {
+		t.Fatalf("should not change state")
+	}
+
+	// Check for a no join message
+	select {
+	case <-ch:
+		t.Fatalf("got bad join message")
+	default:
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+}
+
+// Serf Bug: GH-58, Meta data does not update
+func TestMemberList_AliveNode_ChangeMeta(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+
+	a := alive{
+		Node:        "test",
+		Addr:        []byte{127, 0, 0, 1},
+		Meta:        []byte("val1"),
+		Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	// Listen only after first join
+	m.config.Events = &ChannelEventDelegate{ch}
+
+	// Make suspect
+	state := m.nodeMap["test"]
+
+	// Should reset to alive now
+	a.Incarnation = 2
+	a.Meta = []byte("val2")
+	m.aliveNode(&a, nil, false)
+
+	// Check updates
+	if bytes.Compare(state.Meta, a.Meta) != 0 {
+		t.Fatalf("meta did not update")
+	}
+
+	// Check for a NotifyUpdate
+	select {
+	case e := <-ch:
+		if e.Event != NodeUpdate {
+			t.Fatalf("bad event: %v", e)
+		}
+		if e.Node != &state.Node {
+			t.Fatalf("bad event: %v", e)
+		}
+		if bytes.Compare(e.Node.Meta, a.Meta) != 0 {
+			t.Fatalf("meta did not update")
+		}
+	default:
+		t.Fatalf("missing event!")
+	}
+
+}
+
+func TestMemberList_AliveNode_Refute(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: m.config.Name, Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, true)
+
+	// Clear queue
+	m.broadcasts.Reset()
+
+	// Conflicting alive
+	s := alive{
+		Node:        m.config.Name,
+		Addr:        []byte{127, 0, 0, 1},
+		Incarnation: 2,
+		Meta:        []byte("foo"),
+	}
+	m.aliveNode(&s, nil, false)
+
+	state := m.nodeMap[m.config.Name]
+	if state.State != stateAlive {
+		t.Fatalf("should still be alive")
+	}
+	if state.Meta != nil {
+		t.Fatalf("meta should still be nil")
+	}
+
+	// Check a broad cast is queued
+	if num := m.broadcasts.NumQueued(); num != 1 {
+		t.Fatalf("expected only one queued message: %d",
+			num)
+	}
+
+	// Should be alive mesg
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != aliveMsg {
+		t.Fatalf("expected queued alive msg")
+	}
+}
+
+func TestMemberList_SuspectNode_NoNode(t *testing.T) {
+	m := GetMemberlist(t)
+	s := suspect{Node: "test", Incarnation: 1}
+	m.suspectNode(&s)
+	if len(m.nodes) != 0 {
+		t.Fatalf("don't expect nodes")
+	}
+}
+
+func TestMemberList_SuspectNode(t *testing.T) {
+	m := GetMemberlist(t)
+	m.config.ProbeInterval = time.Millisecond
+	m.config.SuspicionMult = 1
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	s := suspect{Node: "test", Incarnation: 1}
+	m.suspectNode(&s)
+
+	if state.State != stateSuspect {
+		t.Fatalf("Bad state")
+	}
+
+	change := state.StateChange
+	if time.Now().Sub(change) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+
+	// Check its a suspect message
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != suspectMsg {
+		t.Fatalf("expected queued suspect msg")
+	}
+
+	// Wait for the timeout
+	time.Sleep(10 * time.Millisecond)
+
+	if state.State != stateDead {
+		t.Fatalf("Bad state")
+	}
+
+	if time.Now().Sub(state.StateChange) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+	if !state.StateChange.After(change) {
+		t.Fatalf("should increment time")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+
+	// Check its a suspect message
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != deadMsg {
+		t.Fatalf("expected queued dead msg")
+	}
+}
+
+func TestMemberList_SuspectNode_DoubleSuspect(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	s := suspect{Node: "test", Incarnation: 1}
+	m.suspectNode(&s)
+
+	if state.State != stateSuspect {
+		t.Fatalf("Bad state")
+	}
+
+	change := state.StateChange
+	if time.Now().Sub(change) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+
+	// clear the broadcast queue
+	m.broadcasts.Reset()
+
+	// Suspect again
+	m.suspectNode(&s)
+
+	if state.StateChange != change {
+		t.Fatalf("unexpected state change")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 0 {
+		t.Fatalf("expected only one queued message")
+	}
+
+}
+
+func TestMemberList_SuspectNode_OldSuspect(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 10}
+	m.aliveNode(&a, nil, false)
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	// Clear queue
+	m.broadcasts.Reset()
+
+	s := suspect{Node: "test", Incarnation: 1}
+	m.suspectNode(&s)
+
+	if state.State != stateAlive {
+		t.Fatalf("Bad state")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 0 {
+		t.Fatalf("expected only one queued message")
+	}
+}
+
+func TestMemberList_SuspectNode_Refute(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: m.config.Name, Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, true)
+
+	// Clear queue
+	m.broadcasts.Reset()
+
+	s := suspect{Node: m.config.Name, Incarnation: 1}
+	m.suspectNode(&s)
+
+	state := m.nodeMap[m.config.Name]
+	if state.State != stateAlive {
+		t.Fatalf("should still be alive")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+
+	// Should be alive mesg
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != aliveMsg {
+		t.Fatalf("expected queued alive msg")
+	}
+}
+
+func TestMemberList_DeadNode_NoNode(t *testing.T) {
+	m := GetMemberlist(t)
+	d := dead{Node: "test", Incarnation: 1}
+	m.deadNode(&d)
+	if len(m.nodes) != 0 {
+		t.Fatalf("don't expect nodes")
+	}
+}
+
+func TestMemberList_DeadNode(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+	m.config.Events = &ChannelEventDelegate{ch}
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	// Read the join event
+	<-ch
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	d := dead{Node: "test", Incarnation: 1}
+	m.deadNode(&d)
+
+	if state.State != stateDead {
+		t.Fatalf("Bad state")
+	}
+
+	change := state.StateChange
+	if time.Now().Sub(change) > time.Second {
+		t.Fatalf("bad change delta")
+	}
+
+	select {
+	case leave := <-ch:
+		if leave.Event != NodeLeave || leave.Node.Name != "test" {
+			t.Fatalf("bad node name")
+		}
+	default:
+		t.Fatalf("no leave message")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+
+	// Check its a suspect message
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != deadMsg {
+		t.Fatalf("expected queued dead msg")
+	}
+}
+
+func TestMemberList_DeadNode_Double(t *testing.T) {
+	ch := make(chan NodeEvent, 1)
+	m := GetMemberlist(t)
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, false)
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	d := dead{Node: "test", Incarnation: 1}
+	m.deadNode(&d)
+
+	// Clear queue
+	m.broadcasts.Reset()
+
+	// Notify after the first dead
+	m.config.Events = &ChannelEventDelegate{ch}
+
+	// Should do nothing
+	d.Incarnation = 2
+	m.deadNode(&d)
+
+	select {
+	case <-ch:
+		t.Fatalf("should not get leave")
+	default:
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 0 {
+		t.Fatalf("expected only one queued message")
+	}
+}
+
+func TestMemberList_DeadNode_OldDead(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 10}
+	m.aliveNode(&a, nil, false)
+
+	state := m.nodeMap["test"]
+	state.StateChange = state.StateChange.Add(-time.Hour)
+
+	d := dead{Node: "test", Incarnation: 1}
+	m.deadNode(&d)
+
+	if state.State != stateAlive {
+		t.Fatalf("Bad state")
+	}
+}
+
+func TestMemberList_DeadNode_AliveReplay(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 10}
+	m.aliveNode(&a, nil, false)
+
+	d := dead{Node: "test", Incarnation: 10}
+	m.deadNode(&d)
+
+	// Replay alive at same incarnation
+	m.aliveNode(&a, nil, false)
+
+	// Should remain dead
+	state, ok := m.nodeMap["test"]
+	if ok && state.State != stateDead {
+		t.Fatalf("Bad state")
+	}
+}
+
+func TestMemberList_DeadNode_Refute(t *testing.T) {
+	m := GetMemberlist(t)
+	a := alive{Node: m.config.Name, Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a, nil, true)
+
+	// Clear queue
+	m.broadcasts.Reset()
+
+	d := dead{Node: m.config.Name, Incarnation: 1}
+	m.deadNode(&d)
+
+	state := m.nodeMap[m.config.Name]
+	if state.State != stateAlive {
+		t.Fatalf("should still be alive")
+	}
+
+	// Check a broad cast is queued
+	if m.broadcasts.NumQueued() != 1 {
+		t.Fatalf("expected only one queued message")
+	}
+
+	// Should be alive mesg
+	if messageType(m.broadcasts.bcQueue[0].b.Message()[0]) != aliveMsg {
+		t.Fatalf("expected queued alive msg")
+	}
+}
+
+func TestMemberList_MergeState(t *testing.T) {
+	m := GetMemberlist(t)
+	a1 := alive{Node: "test1", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
+	m.aliveNode(&a1, nil, false)
+	a2 := alive{Node: "test2", Addr: []byte{127, 0, 0, 2}, Incarnation: 1}
+	m.aliveNode(&a2, nil, false)
+	a3 := alive{Node: "test3", Addr: []byte{127, 0, 0, 3}, Incarnation: 1}
+	m.aliveNode(&a3, nil, false)
+
+	s := suspect{Node: "test1", Incarnation: 1}
+	m.suspectNode(&s)
+
+	remote := []pushNodeState{
+		pushNodeState{
+			Name:        "test1",
+			Addr:        []byte{127, 0, 0, 1},
+			Incarnation: 2,
+			State:       stateAlive,
+		},
+		pushNodeState{
+			Name:        "test2",
+			Addr:        []byte{127, 0, 0, 2},
+			Incarnation: 1,
+			State:       stateSuspect,
+		},
+		pushNodeState{
+			Name:        "test3",
+			Addr:        []byte{127, 0, 0, 3},
+			Incarnation: 1,
+			State:       stateDead,
+		},
+		pushNodeState{
+			Name:        "test4",
+			Addr:        []byte{127, 0, 0, 4},
+			Incarnation: 2,
+			State:       stateAlive,
+		},
+	}
+
+	// Listen for changes
+	eventCh := make(chan NodeEvent, 1)
+	m.config.Events = &ChannelEventDelegate{eventCh}
+
+	// Merge remote state
+	m.mergeState(remote)
+
+	// Check the states
+	state := m.nodeMap["test1"]
+	if state.State != stateAlive || state.Incarnation != 2 {
+		t.Fatalf("Bad state %v", state)
+	}
+
+	state = m.nodeMap["test2"]
+	if state.State != stateSuspect || state.Incarnation != 1 {
+		t.Fatalf("Bad state %v", state)
+	}
+
+	state = m.nodeMap["test3"]
+	if state.State != stateSuspect {
+		t.Fatalf("Bad state %v", state)
+	}
+
+	state = m.nodeMap["test4"]
+	if state.State != stateAlive || state.Incarnation != 2 {
+		t.Fatalf("Bad state %v", state)
+	}
+
+	// Check the channels
+	select {
+	case e := <-eventCh:
+		if e.Event != NodeJoin || e.Node.Name != "test4" {
+			t.Fatalf("bad node %v", e)
+		}
+	default:
+		t.Fatalf("Expect join")
+	}
+
+	select {
+	case e := <-eventCh:
+		t.Fatalf("Unexpect event: %v", e)
+	default:
+	}
+}
+
+func TestMemberlist_Gossip(t *testing.T) {
+	ch := make(chan NodeEvent, 3)
+
+	addr1 := getBindAddr()
+	addr2 := getBindAddr()
+	ip1 := []byte(addr1)
+	ip2 := []byte(addr2)
+
+	m1 := HostMemberlist(addr1.String(), t, func(c *Config) {
+		c.GossipInterval = time.Millisecond
+	})
+	m2 := HostMemberlist(addr2.String(), t, func(c *Config) {
+		c.Events = &ChannelEventDelegate{ch}
+		c.GossipInterval = time.Millisecond
+	})
+
+	defer m1.Shutdown()
+	defer m2.Shutdown()
+
+	a1 := alive{Node: addr1.String(), Addr: ip1, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a1, nil, true)
+	a2 := alive{Node: addr2.String(), Addr: ip2, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a2, nil, false)
+	a3 := alive{Node: "172.0.0.1", Addr: []byte{172, 0, 0, 1}, Incarnation: 1}
+	m1.aliveNode(&a3, nil, false)
+
+	// Gossip should send all this to m2
+	m1.gossip()
+
+	for i := 0; i < 3; i++ {
+		select {
+		case <-ch:
+		case <-time.After(50 * time.Millisecond):
+			t.Fatalf("timeout")
+		}
+	}
+}
+
+func TestMemberlist_PushPull(t *testing.T) {
+	addr1 := getBindAddr()
+	addr2 := getBindAddr()
+	ip1 := []byte(addr1)
+	ip2 := []byte(addr2)
+
+	ch := make(chan NodeEvent, 3)
+
+	m1 := HostMemberlist(addr1.String(), t, func(c *Config) {
+		c.GossipInterval = 10 * time.Second
+		c.PushPullInterval = time.Millisecond
+	})
+	m2 := HostMemberlist(addr2.String(), t, func(c *Config) {
+		c.GossipInterval = 10 * time.Second
+		c.Events = &ChannelEventDelegate{ch}
+	})
+
+	defer m1.Shutdown()
+	defer m2.Shutdown()
+
+	a1 := alive{Node: addr1.String(), Addr: ip1, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a1, nil, true)
+	a2 := alive{Node: addr2.String(), Addr: ip2, Port: 7946, Incarnation: 1}
+	m1.aliveNode(&a2, nil, false)
+
+	// Gossip should send all this to m2
+	m1.pushPull()
+
+	for i := 0; i < 2; i++ {
+		select {
+		case <-ch:
+		case <-time.After(10 * time.Millisecond):
+			t.Fatalf("timeout")
+		}
+	}
+}
+
+func TestVerifyProtocol(t *testing.T) {
+	cases := []struct {
+		Anodes   [][3]uint8
+		Bnodes   [][3]uint8
+		expected bool
+	}{
+		// Both running identical everything
+		{
+			Anodes: [][3]uint8{
+				{0, 0, 0},
+			},
+			Bnodes: [][3]uint8{
+				{0, 0, 0},
+			},
+			expected: true,
+		},
+
+		// One can understand newer, but speaking same protocol
+		{
+			Anodes: [][3]uint8{
+				{0, 0, 0},
+			},
+			Bnodes: [][3]uint8{
+				{0, 1, 0},
+			},
+			expected: true,
+		},
+
+		// One is speaking outside the range
+		{
+			Anodes: [][3]uint8{
+				{0, 0, 0},
+			},
+			Bnodes: [][3]uint8{
+				{1, 1, 1},
+			},
+			expected: false,
+		},
+
+		// Transitively outside the range
+		{
+			Anodes: [][3]uint8{
+				{0, 1, 0},
+				{0, 2, 1},
+			},
+			Bnodes: [][3]uint8{
+				{1, 3, 1},
+			},
+			expected: false,
+		},
+
+		// Multi-node
+		{
+			Anodes: [][3]uint8{
+				{0, 3, 2},
+				{0, 2, 0},
+			},
+			Bnodes: [][3]uint8{
+				{0, 2, 1},
+				{0, 5, 0},
+			},
+			expected: true,
+		},
+	}
+
+	for _, tc := range cases {
+		aCore := make([][6]uint8, len(tc.Anodes))
+		aApp := make([][6]uint8, len(tc.Anodes))
+		for i, n := range tc.Anodes {
+			aCore[i] = [6]uint8{n[0], n[1], n[2], 0, 0, 0}
+			aApp[i] = [6]uint8{0, 0, 0, n[0], n[1], n[2]}
+		}
+
+		bCore := make([][6]uint8, len(tc.Bnodes))
+		bApp := make([][6]uint8, len(tc.Bnodes))
+		for i, n := range tc.Bnodes {
+			bCore[i] = [6]uint8{n[0], n[1], n[2], 0, 0, 0}
+			bApp[i] = [6]uint8{0, 0, 0, n[0], n[1], n[2]}
+		}
+
+		// Test core protocol verification
+		testVerifyProtocolSingle(t, aCore, bCore, tc.expected)
+		testVerifyProtocolSingle(t, bCore, aCore, tc.expected)
+
+		//  Test app protocol verification
+		testVerifyProtocolSingle(t, aApp, bApp, tc.expected)
+		testVerifyProtocolSingle(t, bApp, aApp, tc.expected)
+	}
+}
+
+func testVerifyProtocolSingle(t *testing.T, A [][6]uint8, B [][6]uint8, expect bool) {
+	m := GetMemberlist(t)
+	defer m.Shutdown()
+
+	m.nodes = make([]*nodeState, len(A))
+	for i, n := range A {
+		m.nodes[i] = &nodeState{
+			Node: Node{
+				PMin: n[0],
+				PMax: n[1],
+				PCur: n[2],
+				DMin: n[3],
+				DMax: n[4],
+				DCur: n[5],
+			},
+		}
+	}
+
+	remote := make([]pushNodeState, len(B))
+	for i, n := range B {
+		remote[i] = pushNodeState{
+			Name: fmt.Sprintf("node %d", i),
+			Vsn:  []uint8{n[0], n[1], n[2], n[3], n[4], n[5]},
+		}
+	}
+
+	err := m.verifyProtocol(remote)
+	if (err == nil) != expect {
+		t.Fatalf("bad:\nA: %v\nB: %v\nErr: %s", A, B, err)
+	}
+}

+ 28 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/test/setup_subnet.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# This script makes sure that 127.0.0.x is routable. On Darwin, there
+# is a bug that it isn't routable and this causes errors.
+#
+
+# Check if loopback is setup
+ping -c 1 -W 10 127.0.0.2 > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+    exit
+fi
+
+# If we're not on OS X, then error
+case $OSTYPE in
+    darwin*)
+        ;;
+    *)
+        echo "Can't setup interfaces on non-Mac. Error!"
+        exit 1
+        ;;
+esac
+
+# Setup loopback
+for ((i=2;i<256;i++))
+do
+    sudo ifconfig lo0 alias 127.0.0.$i up
+done

+ 6 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/todo.md

@@ -0,0 +1,6 @@
+# TODO
+* Dynamic RTT discovery
+    * Compute 99th percentile for ping/ack
+    * Better lower bound for ping/ack, faster failure detection
+* Dynamic MTU discovery
+    * Prevent lost updates, increases efficiency

+ 325 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/util.go

@@ -0,0 +1,325 @@
+package memberlist
+
+import (
+	"bytes"
+	"compress/lzw"
+	"encoding/binary"
+	"fmt"
+	"github.com/hashicorp/go-msgpack/codec"
+	"io"
+	"math"
+	"math/rand"
+	"net"
+	"time"
+)
+
+// pushPullScale is the minimum number of nodes
+// before we start scaling the push/pull timing. The scale
+// effect is the log2(Nodes) - log2(pushPullScale). This means
+// that the 33rd node will cause us to double the interval,
+// while the 65th will triple it.
+const pushPullScaleThreshold = 32
+
+/*
+ * Contains an entry for each private block:
+ * 10.0.0.0/8
+ * 172.16.0.0/12
+ * 192.168/16
+ */
+var privateBlocks []*net.IPNet
+
+var loopbackBlock *net.IPNet
+
+const (
+	// Constant litWidth 2-8
+	lzwLitWidth = 8
+)
+
+func init() {
+	// Seed the random number generator
+	rand.Seed(time.Now().UnixNano())
+
+	// Add each private block
+	privateBlocks = make([]*net.IPNet, 3)
+	_, block, err := net.ParseCIDR("10.0.0.0/8")
+	if err != nil {
+		panic(fmt.Sprintf("Bad cidr. Got %v", err))
+	}
+	privateBlocks[0] = block
+
+	_, block, err = net.ParseCIDR("172.16.0.0/12")
+	if err != nil {
+		panic(fmt.Sprintf("Bad cidr. Got %v", err))
+	}
+	privateBlocks[1] = block
+
+	_, block, err = net.ParseCIDR("192.168.0.0/16")
+	if err != nil {
+		panic(fmt.Sprintf("Bad cidr. Got %v", err))
+	}
+	privateBlocks[2] = block
+
+	_, block, err = net.ParseCIDR("127.0.0.0/8")
+	if err != nil {
+		panic(fmt.Sprintf("Bad cidr. Got %v", err))
+	}
+	loopbackBlock = block
+}
+
+// Decode reverses the encode operation on a byte slice input
+func decode(buf []byte, out interface{}) error {
+	r := bytes.NewReader(buf)
+	hd := codec.MsgpackHandle{}
+	dec := codec.NewDecoder(r, &hd)
+	return dec.Decode(out)
+}
+
+// Encode writes an encoded object to a new bytes buffer
+func encode(msgType messageType, in interface{}) (*bytes.Buffer, error) {
+	buf := bytes.NewBuffer(nil)
+	buf.WriteByte(uint8(msgType))
+	hd := codec.MsgpackHandle{}
+	enc := codec.NewEncoder(buf, &hd)
+	err := enc.Encode(in)
+	return buf, err
+}
+
+// Returns a random offset between 0 and n
+func randomOffset(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return int(rand.Uint32() % uint32(n))
+}
+
+// suspicionTimeout computes the timeout that should be used when
+// a node is suspected
+func suspicionTimeout(suspicionMult, n int, interval time.Duration) time.Duration {
+	nodeScale := math.Ceil(math.Log10(float64(n + 1)))
+	timeout := time.Duration(suspicionMult) * time.Duration(nodeScale) * interval
+	return timeout
+}
+
+// retransmitLimit computes the limit of retransmissions
+func retransmitLimit(retransmitMult, n int) int {
+	nodeScale := math.Ceil(math.Log10(float64(n + 1)))
+	limit := retransmitMult * int(nodeScale)
+	return limit
+}
+
+// shuffleNodes randomly shuffles the input nodes
+func shuffleNodes(nodes []*nodeState) {
+	for i := range nodes {
+		j := rand.Intn(i + 1)
+		nodes[i], nodes[j] = nodes[j], nodes[i]
+	}
+}
+
+// pushPushScale is used to scale the time interval at which push/pull
+// syncs take place. It is used to prevent network saturation as the
+// cluster size grows
+func pushPullScale(interval time.Duration, n int) time.Duration {
+	// Don't scale until we cross the threshold
+	if n <= pushPullScaleThreshold {
+		return interval
+	}
+
+	multiplier := math.Ceil(math.Log2(float64(n))-math.Log2(pushPullScaleThreshold)) + 1.0
+	return time.Duration(multiplier) * interval
+}
+
+// moveDeadNodes moves all the nodes in the dead state
+// to the end of the slice and returns the index of the first dead node.
+func moveDeadNodes(nodes []*nodeState) int {
+	numDead := 0
+	n := len(nodes)
+	for i := 0; i < n-numDead; i++ {
+		if nodes[i].State != stateDead {
+			continue
+		}
+
+		// Move this node to the end
+		nodes[i], nodes[n-numDead-1] = nodes[n-numDead-1], nodes[i]
+		numDead++
+		i--
+	}
+	return n - numDead
+}
+
+// kRandomNodes is used to select up to k random nodes, excluding a given
+// node and any non-alive nodes. It is possible that less than k nodes are returned.
+func kRandomNodes(k int, excludes []string, nodes []*nodeState) []*nodeState {
+	n := len(nodes)
+	kNodes := make([]*nodeState, 0, k)
+OUTER:
+	// Probe up to 3*n times, with large n this is not necessary
+	// since k << n, but with small n we want search to be
+	// exhaustive
+	for i := 0; i < 3*n && len(kNodes) < k; i++ {
+		// Get random node
+		idx := randomOffset(n)
+		node := nodes[idx]
+
+		// Exclude node if match
+		for _, exclude := range excludes {
+			if node.Name == exclude {
+				continue OUTER
+			}
+		}
+
+		// Exclude if not alive
+		if node.State != stateAlive {
+			continue
+		}
+
+		// Check if we have this node already
+		for j := 0; j < len(kNodes); j++ {
+			if node == kNodes[j] {
+				continue OUTER
+			}
+		}
+
+		// Append the node
+		kNodes = append(kNodes, node)
+	}
+	return kNodes
+}
+
+// makeCompoundMessage takes a list of messages and generates
+// a single compound message containing all of them
+func makeCompoundMessage(msgs [][]byte) *bytes.Buffer {
+	// Create a local buffer
+	buf := bytes.NewBuffer(nil)
+
+	// Write out the type
+	buf.WriteByte(uint8(compoundMsg))
+
+	// Write out the number of message
+	buf.WriteByte(uint8(len(msgs)))
+
+	// Add the message lengths
+	for _, m := range msgs {
+		binary.Write(buf, binary.BigEndian, uint16(len(m)))
+	}
+
+	// Append the messages
+	for _, m := range msgs {
+		buf.Write(m)
+	}
+
+	return buf
+}
+
+// decodeCompoundMessage splits a compound message and returns
+// the slices of individual messages. Also returns the number
+// of truncated messages and any potential error
+func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
+	if len(buf) < 1 {
+		err = fmt.Errorf("missing compound length byte")
+		return
+	}
+	numParts := uint8(buf[0])
+	buf = buf[1:]
+
+	// Check we have enough bytes
+	if len(buf) < int(numParts*2) {
+		err = fmt.Errorf("truncated len slice")
+		return
+	}
+
+	// Decode the lengths
+	lengths := make([]uint16, numParts)
+	for i := 0; i < int(numParts); i++ {
+		lengths[i] = binary.BigEndian.Uint16(buf[i*2 : i*2+2])
+	}
+	buf = buf[numParts*2:]
+
+	// Split each message
+	for idx, msgLen := range lengths {
+		if len(buf) < int(msgLen) {
+			trunc = int(numParts) - idx
+			return
+		}
+
+		// Extract the slice, seek past on the buffer
+		slice := buf[:msgLen]
+		buf = buf[msgLen:]
+		parts = append(parts, slice)
+	}
+	return
+}
+
+// Returns if the given IP is in a private block
+func isPrivateIP(ip_str string) bool {
+	ip := net.ParseIP(ip_str)
+	for _, priv := range privateBlocks {
+		if priv.Contains(ip) {
+			return true
+		}
+	}
+	return false
+}
+
+// Returns if the given IP is in a loopback block
+func isLoopbackIP(ip_str string) bool {
+	ip := net.ParseIP(ip_str)
+	return loopbackBlock.Contains(ip)
+}
+
+// compressPayload takes an opaque input buffer, compresses it
+// and wraps it in a compress{} message that is encoded.
+func compressPayload(inp []byte) (*bytes.Buffer, error) {
+	var buf bytes.Buffer
+	compressor := lzw.NewWriter(&buf, lzw.LSB, lzwLitWidth)
+
+	_, err := compressor.Write(inp)
+	if err != nil {
+		return nil, err
+	}
+
+	// Ensure we flush everything out
+	if err := compressor.Close(); err != nil {
+		return nil, err
+	}
+
+	// Create a compressed message
+	c := compress{
+		Algo: lzwAlgo,
+		Buf:  buf.Bytes(),
+	}
+	return encode(compressMsg, &c)
+}
+
+// decompressPayload is used to unpack an encoded compress{}
+// message and return its payload uncompressed
+func decompressPayload(msg []byte) ([]byte, error) {
+	// Decode the message
+	var c compress
+	if err := decode(msg, &c); err != nil {
+		return nil, err
+	}
+	return decompressBuffer(&c)
+}
+
+// decompressBuffer is used to decompress the buffer of
+// a single compress message, handling multiple algorithms
+func decompressBuffer(c *compress) ([]byte, error) {
+	// Verify the algorithm
+	if c.Algo != lzwAlgo {
+		return nil, fmt.Errorf("Cannot decompress unknown algorithm %d", c.Algo)
+	}
+
+	// Create a uncompressor
+	uncomp := lzw.NewReader(bytes.NewReader(c.Buf), lzw.LSB, lzwLitWidth)
+	defer uncomp.Close()
+
+	// Read all the data
+	var b bytes.Buffer
+	_, err := io.Copy(&b, uncomp)
+	if err != nil {
+		return nil, err
+	}
+
+	// Return the uncompressed bytes
+	return b.Bytes(), nil
+}

+ 293 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/memberlist/util_test.go

@@ -0,0 +1,293 @@
+package memberlist
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestEncodeDecode(t *testing.T) {
+	msg := &ping{SeqNo: 100}
+	buf, err := encode(pingMsg, msg)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	var out ping
+	if err := decode(buf.Bytes()[1:], &out); err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	if msg.SeqNo != out.SeqNo {
+		t.Fatalf("bad sequence no")
+	}
+}
+
+func TestRandomOffset(t *testing.T) {
+	vals := make(map[int]struct{})
+	for i := 0; i < 100; i++ {
+		offset := randomOffset(2 << 30)
+		if _, ok := vals[offset]; ok {
+			t.Fatalf("got collision")
+		}
+		vals[offset] = struct{}{}
+	}
+}
+
+func TestRandomOffset_Zero(t *testing.T) {
+	offset := randomOffset(0)
+	if offset != 0 {
+		t.Fatalf("bad offset")
+	}
+}
+
+func TestSuspicionTimeout(t *testing.T) {
+	timeout := suspicionTimeout(3, 10, time.Second)
+	if timeout != 6*time.Second {
+		t.Fatalf("bad timeout")
+	}
+}
+
+func TestRetransmitLimit(t *testing.T) {
+	lim := retransmitLimit(3, 0)
+	if lim != 0 {
+		t.Fatalf("bad val %v", lim)
+	}
+	lim = retransmitLimit(3, 1)
+	if lim != 3 {
+		t.Fatalf("bad val %v", lim)
+	}
+	lim = retransmitLimit(3, 99)
+	if lim != 6 {
+		t.Fatalf("bad val %v", lim)
+	}
+}
+
+func TestShuffleNodes(t *testing.T) {
+	orig := []*nodeState{
+		&nodeState{
+			State: stateDead,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateDead,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateDead,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+	}
+	nodes := make([]*nodeState, len(orig))
+	copy(nodes[:], orig[:])
+
+	if !reflect.DeepEqual(nodes, orig) {
+		t.Fatalf("should match")
+	}
+
+	shuffleNodes(nodes)
+
+	if reflect.DeepEqual(nodes, orig) {
+		t.Fatalf("should not match")
+	}
+}
+
+func TestPushPullScale(t *testing.T) {
+	sec := time.Second
+	for i := 0; i <= 32; i++ {
+		if s := pushPullScale(sec, i); s != sec {
+			t.Fatalf("Bad time scale: %v", s)
+		}
+	}
+	for i := 33; i <= 64; i++ {
+		if s := pushPullScale(sec, i); s != 2*sec {
+			t.Fatalf("Bad time scale: %v", s)
+		}
+	}
+	for i := 65; i <= 128; i++ {
+		if s := pushPullScale(sec, i); s != 3*sec {
+			t.Fatalf("Bad time scale: %v", s)
+		}
+	}
+}
+
+func TestMoveDeadNodes(t *testing.T) {
+	nodes := []*nodeState{
+		&nodeState{
+			State: stateDead,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+		&nodeState{
+			State: stateDead,
+		},
+		&nodeState{
+			State: stateAlive,
+		},
+	}
+
+	idx := moveDeadNodes(nodes)
+	if idx != 3 {
+		t.Fatalf("bad index")
+	}
+	for i := 0; i < idx; i++ {
+		if nodes[i].State != stateAlive {
+			t.Fatalf("Bad state %d", i)
+		}
+	}
+	for i := idx; i < len(nodes); i++ {
+		if nodes[i].State != stateDead {
+			t.Fatalf("Bad state %d", i)
+		}
+	}
+}
+
+func TestKRandomNodes(t *testing.T) {
+	nodes := []*nodeState{}
+	for i := 0; i < 90; i++ {
+		// Half the nodes are in a bad state
+		state := stateAlive
+		switch i % 3 {
+		case 0:
+			state = stateAlive
+		case 1:
+			state = stateSuspect
+		case 2:
+			state = stateDead
+		}
+		nodes = append(nodes, &nodeState{
+			Node: Node{
+				Name: fmt.Sprintf("test%d", i),
+			},
+			State: state,
+		})
+	}
+
+	s1 := kRandomNodes(3, []string{"test0"}, nodes)
+	s2 := kRandomNodes(3, []string{"test0"}, nodes)
+	s3 := kRandomNodes(3, []string{"test0"}, nodes)
+
+	if reflect.DeepEqual(s1, s2) {
+		t.Fatalf("unexpected equal")
+	}
+	if reflect.DeepEqual(s1, s3) {
+		t.Fatalf("unexpected equal")
+	}
+	if reflect.DeepEqual(s2, s3) {
+		t.Fatalf("unexpected equal")
+	}
+
+	for _, s := range [][]*nodeState{s1, s2, s3} {
+		if len(s) != 3 {
+			t.Fatalf("bad len")
+		}
+		for _, n := range s {
+			if n.Name == "test0" {
+				t.Fatalf("Bad name")
+			}
+			if n.State != stateAlive {
+				t.Fatalf("Bad state")
+			}
+		}
+	}
+}
+
+func TestMakeCompoundMessage(t *testing.T) {
+	msg := &ping{SeqNo: 100}
+	buf, err := encode(pingMsg, msg)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
+	compound := makeCompoundMessage(msgs)
+
+	if compound.Len() != 3*buf.Len()+3*compoundOverhead+compoundHeaderOverhead {
+		t.Fatalf("bad len")
+	}
+}
+
+func TestDecodeCompoundMessage(t *testing.T) {
+	msg := &ping{SeqNo: 100}
+	buf, err := encode(pingMsg, msg)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
+	compound := makeCompoundMessage(msgs)
+
+	trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:])
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	if trunc != 0 {
+		t.Fatalf("should not truncate")
+	}
+	if len(parts) != 3 {
+		t.Fatalf("bad parts")
+	}
+	for _, p := range parts {
+		if len(p) != buf.Len() {
+			t.Fatalf("bad part len")
+		}
+	}
+}
+
+func TestDecodeCompoundMessage_Trunc(t *testing.T) {
+	msg := &ping{SeqNo: 100}
+	buf, err := encode(pingMsg, msg)
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	msgs := [][]byte{buf.Bytes(), buf.Bytes(), buf.Bytes()}
+	compound := makeCompoundMessage(msgs)
+
+	trunc, parts, err := decodeCompoundMessage(compound.Bytes()[1:38])
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+	if trunc != 1 {
+		t.Fatalf("truncate: %d", trunc)
+	}
+	if len(parts) != 2 {
+		t.Fatalf("bad parts")
+	}
+	for _, p := range parts {
+		if len(p) != buf.Len() {
+			t.Fatalf("bad part len")
+		}
+	}
+}
+
+func TestCompressDecompressPayload(t *testing.T) {
+	buf, err := compressPayload([]byte("testing"))
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	decomp, err := decompressPayload(buf.Bytes()[1:])
+	if err != nil {
+		t.Fatalf("unexpected err: %s", err)
+	}
+
+	if !reflect.DeepEqual(decomp, []byte("testing")) {
+		t.Fatalf("bad payload: %v", decomp)
+	}
+}

+ 27 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/broadcast.go

@@ -0,0 +1,27 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+)
+
+// broadcast is an implementation of memberlist.Broadcast and is used
+// to manage broadcasts across the memberlist channel that are related
+// only to Serf.
+type broadcast struct {
+	msg    []byte
+	notify chan<- struct{}
+}
+
+func (b *broadcast) Invalidates(other memberlist.Broadcast) bool {
+	return false
+}
+
+func (b *broadcast) Message() []byte {
+	return b.msg
+}
+
+func (b *broadcast) Finished() {
+	if b.notify != nil {
+		close(b.notify)
+	}
+}

+ 32 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/broadcast_test.go

@@ -0,0 +1,32 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+	"testing"
+	"time"
+)
+
+func TestBroadcast_Impl(t *testing.T) {
+	var _ memberlist.Broadcast = &broadcast{}
+}
+
+func TestBroadcastFinished(t *testing.T) {
+	t.Parallel()
+
+	ch := make(chan struct{})
+	b := &broadcast{notify: ch}
+	b.Finished()
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatalf("should have notified")
+	}
+}
+
+func TestBroadcastFinished_nilNotify(t *testing.T) {
+	t.Parallel()
+
+	b := &broadcast{notify: nil}
+	b.Finished()
+}

+ 80 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce.go

@@ -0,0 +1,80 @@
+package serf
+
+import (
+	"time"
+)
+
+// coalescer is a simple interface that must be implemented to be
+// used inside of a coalesceLoop
+type coalescer interface {
+	// Can the coalescer handle this event, if not it is
+	// directly passed through to the destination channel
+	Handle(Event) bool
+
+	// Invoked to coalesce the given event
+	Coalesce(Event)
+
+	// Invoked to flush the coalesced events
+	Flush(outChan chan<- Event)
+}
+
+// coalescedEventCh returns an event channel where the events are coalesced
+// using the given coalescer.
+func coalescedEventCh(outCh chan<- Event, shutdownCh <-chan struct{},
+	cPeriod time.Duration, qPeriod time.Duration, c coalescer) chan<- Event {
+	inCh := make(chan Event, 1024)
+	go coalesceLoop(inCh, outCh, shutdownCh, cPeriod, qPeriod, c)
+	return inCh
+}
+
+// coalesceLoop is a simple long-running routine that manages the high-level
+// flow of coalescing based on quiescence and a maximum quantum period.
+func coalesceLoop(inCh <-chan Event, outCh chan<- Event, shutdownCh <-chan struct{},
+	coalescePeriod time.Duration, quiescentPeriod time.Duration, c coalescer) {
+	var quiescent <-chan time.Time
+	var quantum <-chan time.Time
+	shutdown := false
+
+INGEST:
+	// Reset the timers
+	quantum = nil
+	quiescent = nil
+
+	for {
+		select {
+		case e := <-inCh:
+			// Ignore any non handled events
+			if !c.Handle(e) {
+				outCh <- e
+				continue
+			}
+
+			// Start a new quantum if we need to
+			// and restart the quiescent timer
+			if quantum == nil {
+				quantum = time.After(coalescePeriod)
+			}
+			quiescent = time.After(quiescentPeriod)
+
+			// Coalesce the event
+			c.Coalesce(e)
+
+		case <-quantum:
+			goto FLUSH
+		case <-quiescent:
+			goto FLUSH
+		case <-shutdownCh:
+			shutdown = true
+			goto FLUSH
+		}
+	}
+
+FLUSH:
+	// Flush the coalesced events
+	c.Flush(outCh)
+
+	// Restart ingestion if we are not done
+	if !shutdown {
+		goto INGEST
+	}
+}

+ 68 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_member.go

@@ -0,0 +1,68 @@
+package serf
+
+type coalesceEvent struct {
+	Type   EventType
+	Member *Member
+}
+
+type memberEventCoalescer struct {
+	lastEvents   map[string]EventType
+	latestEvents map[string]coalesceEvent
+}
+
+func (c *memberEventCoalescer) Handle(e Event) bool {
+	switch e.EventType() {
+	case EventMemberJoin:
+		return true
+	case EventMemberLeave:
+		return true
+	case EventMemberFailed:
+		return true
+	case EventMemberUpdate:
+		return true
+	case EventMemberReap:
+		return true
+	default:
+		return false
+	}
+}
+
+func (c *memberEventCoalescer) Coalesce(raw Event) {
+	e := raw.(MemberEvent)
+	for _, m := range e.Members {
+		c.latestEvents[m.Name] = coalesceEvent{
+			Type:   e.Type,
+			Member: &m,
+		}
+	}
+}
+
+func (c *memberEventCoalescer) Flush(outCh chan<- Event) {
+	// Coalesce the various events we got into a single set of events.
+	events := make(map[EventType]*MemberEvent)
+	for name, cevent := range c.latestEvents {
+		previous, ok := c.lastEvents[name]
+
+		// If we sent the same event before, then ignore
+		// unless it is a MemberUpdate
+		if ok && previous == cevent.Type && cevent.Type != EventMemberUpdate {
+			continue
+		}
+
+		// Update our last event
+		c.lastEvents[name] = cevent.Type
+
+		// Add it to our event
+		newEvent, ok := events[cevent.Type]
+		if !ok {
+			newEvent = &MemberEvent{Type: cevent.Type}
+			events[cevent.Type] = newEvent
+		}
+		newEvent.Members = append(newEvent.Members, *cevent.Member)
+	}
+
+	// Send out those events
+	for _, event := range events {
+		outCh <- *event
+	}
+}

+ 185 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_member_test.go

@@ -0,0 +1,185 @@
+package serf
+
+import (
+	"reflect"
+	"sort"
+	"testing"
+	"time"
+)
+
+func TestMemberEventCoalesce_Basic(t *testing.T) {
+	outCh := make(chan Event, 64)
+	shutdownCh := make(chan struct{})
+	defer close(shutdownCh)
+
+	c := &memberEventCoalescer{
+		lastEvents:   make(map[string]EventType),
+		latestEvents: make(map[string]coalesceEvent),
+	}
+
+	inCh := coalescedEventCh(outCh, shutdownCh,
+		5*time.Millisecond, 5*time.Millisecond, c)
+
+	send := []Event{
+		MemberEvent{
+			Type:    EventMemberJoin,
+			Members: []Member{Member{Name: "foo"}},
+		},
+		MemberEvent{
+			Type:    EventMemberLeave,
+			Members: []Member{Member{Name: "foo"}},
+		},
+		MemberEvent{
+			Type:    EventMemberLeave,
+			Members: []Member{Member{Name: "bar"}},
+		},
+		MemberEvent{
+			Type:    EventMemberUpdate,
+			Members: []Member{Member{Name: "zip", Tags: map[string]string{"role": "foo"}}},
+		},
+		MemberEvent{
+			Type:    EventMemberUpdate,
+			Members: []Member{Member{Name: "zip", Tags: map[string]string{"role": "bar"}}},
+		},
+		MemberEvent{
+			Type:    EventMemberReap,
+			Members: []Member{Member{Name: "dead"}},
+		},
+	}
+
+	for _, e := range send {
+		inCh <- e
+	}
+
+	events := make(map[EventType]Event)
+	timeout := time.After(10 * time.Millisecond)
+
+MEMBEREVENTFORLOOP:
+	for {
+		select {
+		case e := <-outCh:
+			events[e.EventType()] = e
+		case <-timeout:
+			break MEMBEREVENTFORLOOP
+		}
+	}
+
+	if len(events) != 3 {
+		t.Fatalf("bad: %#v", events)
+	}
+
+	if e, ok := events[EventMemberLeave]; !ok {
+		t.Fatalf("bad: %#v", events)
+	} else {
+		me := e.(MemberEvent)
+
+		if len(me.Members) != 2 {
+			t.Fatalf("bad: %#v", me)
+		}
+
+		expected := []string{"bar", "foo"}
+		names := []string{me.Members[0].Name, me.Members[1].Name}
+		sort.Strings(names)
+
+		if !reflect.DeepEqual(expected, names) {
+			t.Fatalf("bad: %#v", names)
+		}
+	}
+
+	if e, ok := events[EventMemberUpdate]; !ok {
+		t.Fatalf("bad: %#v", events)
+	} else {
+		me := e.(MemberEvent)
+		if len(me.Members) != 1 {
+			t.Fatalf("bad: %#v", me)
+		}
+
+		if me.Members[0].Name != "zip" {
+			t.Fatalf("bad: %#v", me.Members)
+		}
+		if me.Members[0].Tags["role"] != "bar" {
+			t.Fatalf("bad: %#v", me.Members[0].Tags)
+		}
+	}
+
+	if e, ok := events[EventMemberReap]; !ok {
+		t.Fatalf("bad: %#v", events)
+	} else {
+		me := e.(MemberEvent)
+		if len(me.Members) != 1 {
+			t.Fatalf("bad: %#v", me)
+		}
+
+		if me.Members[0].Name != "dead" {
+			t.Fatalf("bad: %#v", me.Members)
+		}
+	}
+}
+
+func TestMemberEventCoalesce_TagUpdate(t *testing.T) {
+	outCh := make(chan Event, 64)
+	shutdownCh := make(chan struct{})
+	defer close(shutdownCh)
+
+	c := &memberEventCoalescer{
+		lastEvents:   make(map[string]EventType),
+		latestEvents: make(map[string]coalesceEvent),
+	}
+
+	inCh := coalescedEventCh(outCh, shutdownCh,
+		5*time.Millisecond, 5*time.Millisecond, c)
+
+	inCh <- MemberEvent{
+		Type:    EventMemberUpdate,
+		Members: []Member{Member{Name: "foo", Tags: map[string]string{"role": "foo"}}},
+	}
+
+	time.Sleep(10 * time.Millisecond)
+
+	select {
+	case e := <-outCh:
+		if e.EventType() != EventMemberUpdate {
+			t.Fatalf("expected update")
+		}
+	default:
+		t.Fatalf("expected update")
+	}
+
+	// Second update should not be suppressed even though
+	// last event was an update
+	inCh <- MemberEvent{
+		Type:    EventMemberUpdate,
+		Members: []Member{Member{Name: "foo", Tags: map[string]string{"role": "bar"}}},
+	}
+	time.Sleep(10 * time.Millisecond)
+
+	select {
+	case e := <-outCh:
+		if e.EventType() != EventMemberUpdate {
+			t.Fatalf("expected update")
+		}
+	default:
+		t.Fatalf("expected update")
+	}
+}
+
+func TestMemberEventCoalesce_passThrough(t *testing.T) {
+	cases := []struct {
+		e      Event
+		handle bool
+	}{
+		{UserEvent{}, false},
+		{MemberEvent{Type: EventMemberJoin}, true},
+		{MemberEvent{Type: EventMemberLeave}, true},
+		{MemberEvent{Type: EventMemberFailed}, true},
+		{MemberEvent{Type: EventMemberUpdate}, true},
+		{MemberEvent{Type: EventMemberReap}, true},
+	}
+
+	for _, tc := range cases {
+		c := &memberEventCoalescer{}
+		if tc.handle != c.Handle(tc.e) {
+			t.Fatalf("bad: %#v", tc.e)
+		}
+	}
+}

+ 140 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_test.go

@@ -0,0 +1,140 @@
+package serf
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+	"time"
+)
+
+// Mock EventCounter type
+const EventCounter EventType = 9000
+
+type counterEvent struct {
+	delta int
+}
+
+func (c counterEvent) EventType() EventType {
+	return EventCounter
+}
+func (c counterEvent) String() string {
+	return fmt.Sprintf("CounterEvent %d", c.delta)
+}
+
+// Mock coalescer
+type mockCoalesce struct {
+	value int
+}
+
+func (c *mockCoalesce) Handle(e Event) bool {
+	return e.EventType() == EventCounter
+}
+
+func (c *mockCoalesce) Coalesce(e Event) {
+	c.value += e.(counterEvent).delta
+}
+
+func (c *mockCoalesce) Flush(outChan chan<- Event) {
+	outChan <- counterEvent{c.value}
+	c.value = 0
+}
+
+func testCoalescer(cPeriod, qPeriod time.Duration) (chan<- Event, <-chan Event, chan<- struct{}) {
+	in := make(chan Event, 64)
+	out := make(chan Event)
+	shutdown := make(chan struct{})
+	c := &mockCoalesce{}
+	go coalesceLoop(in, out, shutdown, cPeriod, qPeriod, c)
+	return in, out, shutdown
+}
+
+func TestCoalescer_basic(t *testing.T) {
+	in, out, shutdown := testCoalescer(5*time.Millisecond, time.Second)
+	defer close(shutdown)
+
+	send := []Event{
+		counterEvent{1},
+		counterEvent{39},
+		counterEvent{2},
+	}
+	for _, e := range send {
+		in <- e
+	}
+
+	select {
+	case e := <-out:
+		if e.EventType() != EventCounter {
+			t.Fatalf("expected counter, got: %d", e.EventType())
+		}
+
+		if e.(counterEvent).delta != 42 {
+			t.Fatalf("bad: %#v", e)
+		}
+
+	case <-time.After(50 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+}
+
+func TestCoalescer_quiescent(t *testing.T) {
+	// This tests the quiescence by creating a long coalescence period
+	// with a short quiescent period and waiting only a multiple of the
+	// quiescent period for results.
+	in, out, shutdown := testCoalescer(10*time.Second, 10*time.Millisecond)
+	defer close(shutdown)
+
+	send := []Event{
+		counterEvent{1},
+		counterEvent{39},
+		counterEvent{2},
+	}
+	for _, e := range send {
+		in <- e
+	}
+
+	select {
+	case e := <-out:
+		if e.EventType() != EventCounter {
+			t.Fatalf("expected counter, got: %d", e.EventType())
+		}
+
+		if e.(counterEvent).delta != 42 {
+			t.Fatalf("bad: %#v", e)
+		}
+	case <-time.After(50 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+}
+
+func TestCoalescer_passThrough(t *testing.T) {
+	in, out, shutdown := testCoalescer(time.Second, time.Second)
+	defer close(shutdown)
+
+	send := []Event{
+		UserEvent{
+			Name:    "test",
+			Payload: []byte("foo"),
+		},
+	}
+
+	for _, e := range send {
+		in <- e
+	}
+
+	select {
+	case e := <-out:
+		if e.EventType() != EventUser {
+			t.Fatalf("expected user event, got: %d", e.EventType())
+		}
+
+		if e.(UserEvent).Name != "test" {
+			t.Fatalf("name should be test. %v", e)
+		}
+
+		if !reflect.DeepEqual([]byte("foo"), e.(UserEvent).Payload) {
+			t.Fatalf("bad: %#v", e.(UserEvent).Payload)
+		}
+	case <-time.After(50 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+}

+ 52 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_user.go

@@ -0,0 +1,52 @@
+package serf
+
+type latestUserEvents struct {
+	LTime  LamportTime
+	Events []Event
+}
+
+type userEventCoalescer struct {
+	// Maps an event name into the latest versions
+	events map[string]*latestUserEvents
+}
+
+func (c *userEventCoalescer) Handle(e Event) bool {
+	// Only handle EventUser messages
+	if e.EventType() != EventUser {
+		return false
+	}
+
+	// Check if coalescing is enabled
+	user := e.(UserEvent)
+	return user.Coalesce
+}
+
+func (c *userEventCoalescer) Coalesce(e Event) {
+	user := e.(UserEvent)
+	latest, ok := c.events[user.Name]
+
+	// Create a new entry if there are none, or
+	// if this message has the newest LTime
+	if !ok || latest.LTime < user.LTime {
+		latest = &latestUserEvents{
+			LTime:  user.LTime,
+			Events: []Event{e},
+		}
+		c.events[user.Name] = latest
+		return
+	}
+
+	// If the the same age, save it
+	if latest.LTime == user.LTime {
+		latest.Events = append(latest.Events, e)
+	}
+}
+
+func (c *userEventCoalescer) Flush(outChan chan<- Event) {
+	for _, latest := range c.events {
+		for _, e := range latest.Events {
+			outChan <- e
+		}
+	}
+	c.events = make(map[string]*latestUserEvents)
+}

+ 102 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/coalesce_user_test.go

@@ -0,0 +1,102 @@
+package serf
+
+import (
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestUserEventCoalesce_Basic(t *testing.T) {
+	outCh := make(chan Event, 64)
+	shutdownCh := make(chan struct{})
+	defer close(shutdownCh)
+
+	c := &userEventCoalescer{
+		events: make(map[string]*latestUserEvents),
+	}
+
+	inCh := coalescedEventCh(outCh, shutdownCh,
+		5*time.Millisecond, 5*time.Millisecond, c)
+
+	send := []Event{
+		UserEvent{
+			LTime:    1,
+			Name:     "foo",
+			Coalesce: true,
+		},
+		UserEvent{
+			LTime:    2,
+			Name:     "foo",
+			Coalesce: true,
+		},
+		UserEvent{
+			LTime:    2,
+			Name:     "bar",
+			Payload:  []byte("test1"),
+			Coalesce: true,
+		},
+		UserEvent{
+			LTime:    2,
+			Name:     "bar",
+			Payload:  []byte("test2"),
+			Coalesce: true,
+		},
+	}
+
+	for _, e := range send {
+		inCh <- e
+	}
+
+	var gotFoo, gotBar1, gotBar2 bool
+	timeout := time.After(10 * time.Millisecond)
+USEREVENTFORLOOP:
+	for {
+		select {
+		case e := <-outCh:
+			ue := e.(UserEvent)
+			switch ue.Name {
+			case "foo":
+				if ue.LTime != 2 {
+					t.Fatalf("bad ltime for foo %#v", ue)
+				}
+				gotFoo = true
+			case "bar":
+				if ue.LTime != 2 {
+					t.Fatalf("bad ltime for bar %#v", ue)
+				}
+				if reflect.DeepEqual(ue.Payload, []byte("test1")) {
+					gotBar1 = true
+				}
+				if reflect.DeepEqual(ue.Payload, []byte("test2")) {
+					gotBar2 = true
+				}
+			}
+		case <-timeout:
+			break USEREVENTFORLOOP
+		}
+	}
+
+	if !gotFoo || !gotBar1 || !gotBar2 {
+		t.Fatalf("missing messages %v %v %v", gotFoo, gotBar1, gotBar2)
+	}
+}
+
+func TestUserEventCoalesce_passThrough(t *testing.T) {
+	cases := []struct {
+		e      Event
+		handle bool
+	}{
+		{UserEvent{Coalesce: false}, false},
+		{UserEvent{Coalesce: true}, true},
+		{MemberEvent{Type: EventMemberJoin}, false},
+		{MemberEvent{Type: EventMemberLeave}, false},
+		{MemberEvent{Type: EventMemberFailed}, false},
+	}
+
+	for _, tc := range cases {
+		c := &userEventCoalescer{}
+		if tc.handle != c.Handle(tc.e) {
+			t.Fatalf("bad: %#v", tc.e)
+		}
+	}
+}

+ 234 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/config.go

@@ -0,0 +1,234 @@
+package serf
+
+import (
+	"io"
+	"os"
+	"time"
+
+	"github.com/hashicorp/memberlist"
+)
+
+// ProtocolVersionMap is the mapping of Serf delegate protocol versions
+// to memberlist protocol versions. We mask the memberlist protocols using
+// our own protocol version.
+var ProtocolVersionMap map[uint8]uint8
+
+func init() {
+	ProtocolVersionMap = map[uint8]uint8{
+		4: 2,
+		3: 2,
+		2: 2,
+	}
+}
+
+// Config is the configuration for creating a Serf instance.
+type Config struct {
+	// The name of this node. This must be unique in the cluster. If this
+	// is not set, Serf will set it to the hostname of the running machine.
+	NodeName string
+
+	// The tags for this role, if any. This is used to provide arbitrary
+	// key/value metadata per-node. For example, a "role" tag may be used to
+	// differentiate "load-balancer" from a "web" role as parts of the same cluster.
+	// Tags are deprecating 'Role', and instead it acts as a special key in this
+	// map.
+	Tags map[string]string
+
+	// EventCh is a channel that receives all the Serf events. The events
+	// are sent on this channel in proper ordering. Care must be taken that
+	// this channel doesn't block, either by processing the events quick
+	// enough or buffering the channel, otherwise it can block state updates
+	// within Serf itself. If no EventCh is specified, no events will be fired,
+	// but point-in-time snapshots of members can still be retrieved by
+	// calling Members on Serf.
+	EventCh chan<- Event
+
+	// ProtocolVersion is the protocol version to speak. This must be between
+	// ProtocolVersionMin and ProtocolVersionMax.
+	ProtocolVersion uint8
+
+	// BroadcastTimeout is the amount of time to wait for a broadcast
+	// message to be sent to the cluster. Broadcast messages are used for
+	// things like leave messages and force remove messages. If this is not
+	// set, a timeout of 5 seconds will be set.
+	BroadcastTimeout time.Duration
+
+	// The settings below relate to Serf's event coalescence feature. Serf
+	// is able to coalesce multiple events into single events in order to
+	// reduce the amount of noise that is sent along the EventCh. For example
+	// if five nodes quickly join, the EventCh will be sent one EventMemberJoin
+	// containing the five nodes rather than five individual EventMemberJoin
+	// events. Coalescence can mitigate potential flapping behavior.
+	//
+	// Coalescence is disabled by default and can be enabled by setting
+	// CoalescePeriod.
+	//
+	// CoalescePeriod specifies the time duration to coalesce events.
+	// For example, if this is set to 5 seconds, then all events received
+	// within 5 seconds that can be coalesced will be.
+	//
+	// QuiescentPeriod specifies the duration of time where if no events
+	// are received, coalescence immediately happens. For example, if
+	// CoalscePeriod is set to 10 seconds but QuiscentPeriod is set to 2
+	// seconds, then the events will be coalesced and dispatched if no
+	// new events are received within 2 seconds of the last event. Otherwise,
+	// every event will always be delayed by at least 10 seconds.
+	CoalescePeriod  time.Duration
+	QuiescentPeriod time.Duration
+
+	// The settings below relate to Serf's user event coalescing feature.
+	// The settings operate like above but only affect user messages and
+	// not the Member* messages that Serf generates.
+	UserCoalescePeriod  time.Duration
+	UserQuiescentPeriod time.Duration
+
+	// The settings below relate to Serf keeping track of recently
+	// failed/left nodes and attempting reconnects.
+	//
+	// ReapInterval is the interval when the reaper runs. If this is not
+	// set (it is zero), it will be set to a reasonable default.
+	//
+	// ReconnectInterval is the interval when we attempt to reconnect
+	// to failed nodes. If this is not set (it is zero), it will be set
+	// to a reasonable default.
+	//
+	// ReconnectTimeout is the amount of time to attempt to reconnect to
+	// a failed node before giving up and considering it completely gone.
+	//
+	// TombstoneTimeout is the amount of time to keep around nodes
+	// that gracefully left as tombstones for syncing state with other
+	// Serf nodes.
+	ReapInterval      time.Duration
+	ReconnectInterval time.Duration
+	ReconnectTimeout  time.Duration
+	TombstoneTimeout  time.Duration
+
+	// QueueDepthWarning is used to generate warning message if the
+	// number of queued messages to broadcast exceeds this number. This
+	// is to provide the user feedback if events are being triggered
+	// faster than they can be disseminated
+	QueueDepthWarning int
+
+	// MaxQueueDepth is used to start dropping messages if the number
+	// of queued messages to broadcast exceeds this number. This is to
+	// prevent an unbounded growth of memory utilization
+	MaxQueueDepth int
+
+	// RecentIntentBuffer is used to set the size of recent join and leave intent
+	// messages that will be buffered. This is used to guard against
+	// the case where Serf broadcasts an intent that arrives before the
+	// Memberlist event. It is important that this not be too small to avoid
+	// continuous rebroadcasting of dead events.
+	RecentIntentBuffer int
+
+	// EventBuffer is used to control how many events are buffered.
+	// This is used to prevent re-delivery of events to a client. The buffer
+	// must be large enough to handle all "recent" events, since Serf will
+	// not deliver messages that are older than the oldest entry in the buffer.
+	// Thus if a client is generating too many events, it's possible that the
+	// buffer gets overrun and messages are not delivered.
+	EventBuffer int
+
+	// QueryBuffer is used to control how many queries are buffered.
+	// This is used to prevent re-delivery of queries to a client. The buffer
+	// must be large enough to handle all "recent" events, since Serf will not
+	// deliver queries older than the oldest entry in the buffer.
+	// Thus if a client is generating too many queries, it's possible that the
+	// buffer gets overrun and messages are not delivered.
+	QueryBuffer int
+
+	// QueryTimeoutMult configures the default timeout multipler for a query to run if no
+	// specific value is provided. Queries are real-time by nature, where the
+	// reply is time sensitive. As a result, results are collected in an async
+	// fashion, however the query must have a bounded duration. We want the timeout
+	// to be long enough that all nodes have time to receive the message, run a handler,
+	// and generate a reply. Once the timeout is exceeded, any further replies are ignored.
+	// The default value is
+	//
+	// Timeout = GossipInterval * QueryTimeoutMult * log(N+1)
+	//
+	QueryTimeoutMult int
+
+	// MemberlistConfig is the memberlist configuration that Serf will
+	// use to do the underlying membership management and gossip. Some
+	// fields in the MemberlistConfig will be overwritten by Serf no
+	// matter what:
+	//
+	//   * Name - This will always be set to the same as the NodeName
+	//     in this configuration.
+	//
+	//   * Events - Serf uses a custom event delegate.
+	//
+	//   * Delegate - Serf uses a custom delegate.
+	//
+	MemberlistConfig *memberlist.Config
+
+	// LogOutput is the location to write logs to. If this is not set,
+	// logs will go to stderr.
+	LogOutput io.Writer
+
+	// SnapshotPath if provided is used to snapshot live nodes as well
+	// as lamport clock values. When Serf is started with a snapshot,
+	// it will attempt to join all the previously known nodes until one
+	// succeeds and will also avoid replaying old user events.
+	SnapshotPath string
+
+	// RejoinAfterLeave controls our interaction with the snapshot file.
+	// When set to false (default), a leave causes a Serf to not rejoin
+	// the cluster until an explicit join is received. If this is set to
+	// true, we ignore the leave, and rejoin the cluster on start.
+	RejoinAfterLeave bool
+
+	// EnableNameConflictResolution controls if Serf will actively attempt
+	// to resolve a name conflict. Since each Serf member must have a unique
+	// name, a cluster can run into issues if multiple nodes claim the same
+	// name. Without automatic resolution, Serf merely logs some warnings, but
+	// otherwise does not take any action. Automatic resolution detects the
+	// conflict and issues a special query which asks the cluster for the
+	// Name -> IP:Port mapping. If there is a simple majority of votes, that
+	// node stays while the other node will leave the cluster and exit.
+	EnableNameConflictResolution bool
+
+	// KeyringFile provides the location of a writable file where Serf can
+	// persist changes to the encryption keyring.
+	KeyringFile string
+
+	// Merge can be optionally provided to intercept a cluster merge
+	// and conditionally abort the merge.
+	Merge MergeDelegate
+}
+
+// Init allocates the subdata structures
+func (c *Config) Init() {
+	if c.Tags == nil {
+		c.Tags = make(map[string]string)
+	}
+}
+
+// DefaultConfig returns a Config struct that contains reasonable defaults
+// for most of the configurations.
+func DefaultConfig() *Config {
+	hostname, err := os.Hostname()
+	if err != nil {
+		panic(err)
+	}
+
+	return &Config{
+		NodeName:                     hostname,
+		BroadcastTimeout:             5 * time.Second,
+		EventBuffer:                  512,
+		QueryBuffer:                  512,
+		LogOutput:                    os.Stderr,
+		ProtocolVersion:              ProtocolVersionMax,
+		ReapInterval:                 15 * time.Second,
+		RecentIntentBuffer:           128,
+		ReconnectInterval:            30 * time.Second,
+		ReconnectTimeout:             24 * time.Hour,
+		QueueDepthWarning:            128,
+		MaxQueueDepth:                4096,
+		TombstoneTimeout:             24 * time.Hour,
+		MemberlistConfig:             memberlist.DefaultLANConfig(),
+		QueryTimeoutMult:             16,
+		EnableNameConflictResolution: true,
+	}
+}

+ 12 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/config_test.go

@@ -0,0 +1,12 @@
+package serf
+
+import (
+	"testing"
+)
+
+func TestDefaultConfig(t *testing.T) {
+	c := DefaultConfig()
+	if c.ProtocolVersion != ProtocolVersionMax {
+		t.Fatalf("bad: %#v", c)
+	}
+}

+ 13 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/conflict_delegate.go

@@ -0,0 +1,13 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+)
+
+type conflictDelegate struct {
+	serf *Serf
+}
+
+func (c *conflictDelegate) NotifyConflict(existing, other *memberlist.Node) {
+	c.serf.handleNodeConflict(existing, other)
+}

+ 247 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/delegate.go

@@ -0,0 +1,247 @@
+package serf
+
+import (
+	"fmt"
+	"github.com/armon/go-metrics"
+)
+
+// delegate is the memberlist.Delegate implementation that Serf uses.
+type delegate struct {
+	serf *Serf
+}
+
+func (d *delegate) NodeMeta(limit int) []byte {
+	roleBytes := d.serf.encodeTags(d.serf.config.Tags)
+	if len(roleBytes) > limit {
+		panic(fmt.Errorf("Node tags '%v' exceeds length limit of %d bytes", d.serf.config.Tags, limit))
+	}
+
+	return roleBytes
+}
+
+func (d *delegate) NotifyMsg(buf []byte) {
+	// If we didn't actually receive any data, then ignore it.
+	if len(buf) == 0 {
+		return
+	}
+	metrics.AddSample([]string{"serf", "msgs", "received"}, float32(len(buf)))
+
+	rebroadcast := false
+	rebroadcastQueue := d.serf.broadcasts
+	t := messageType(buf[0])
+	switch t {
+	case messageLeaveType:
+		var leave messageLeave
+		if err := decodeMessage(buf[1:], &leave); err != nil {
+			d.serf.logger.Printf("[ERR] serf: Error decoding leave message: %s", err)
+			break
+		}
+
+		d.serf.logger.Printf("[DEBUG] serf: messageLeaveType: %s", leave.Node)
+		rebroadcast = d.serf.handleNodeLeaveIntent(&leave)
+
+	case messageJoinType:
+		var join messageJoin
+		if err := decodeMessage(buf[1:], &join); err != nil {
+			d.serf.logger.Printf("[ERR] serf: Error decoding join message: %s", err)
+			break
+		}
+
+		d.serf.logger.Printf("[DEBUG] serf: messageJoinType: %s", join.Node)
+		rebroadcast = d.serf.handleNodeJoinIntent(&join)
+
+	case messageUserEventType:
+		var event messageUserEvent
+		if err := decodeMessage(buf[1:], &event); err != nil {
+			d.serf.logger.Printf("[ERR] serf: Error decoding user event message: %s", err)
+			break
+		}
+
+		d.serf.logger.Printf("[DEBUG] serf: messageUserEventType: %s", event.Name)
+		rebroadcast = d.serf.handleUserEvent(&event)
+		rebroadcastQueue = d.serf.eventBroadcasts
+
+	case messageQueryType:
+		var query messageQuery
+		if err := decodeMessage(buf[1:], &query); err != nil {
+			d.serf.logger.Printf("[ERR] serf: Error decoding query message: %s", err)
+			break
+		}
+
+		d.serf.logger.Printf("[DEBUG] serf: messageQueryType: %s", query.Name)
+		rebroadcast = d.serf.handleQuery(&query)
+		rebroadcastQueue = d.serf.queryBroadcasts
+
+	case messageQueryResponseType:
+		var resp messageQueryResponse
+		if err := decodeMessage(buf[1:], &resp); err != nil {
+			d.serf.logger.Printf("[ERR] serf: Error decoding query response message: %s", err)
+			break
+		}
+
+		d.serf.logger.Printf("[DEBUG] serf: messageQueryResponseType: %v", resp.From)
+		d.serf.handleQueryResponse(&resp)
+
+	default:
+		d.serf.logger.Printf("[WARN] serf: Received message of unknown type: %d", t)
+	}
+
+	if rebroadcast {
+		// Copy the buffer since it we cannot rely on the slice not changing
+		newBuf := make([]byte, len(buf))
+		copy(newBuf, buf)
+
+		rebroadcastQueue.QueueBroadcast(&broadcast{
+			msg:    newBuf,
+			notify: nil,
+		})
+	}
+}
+
+func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte {
+	msgs := d.serf.broadcasts.GetBroadcasts(overhead, limit)
+
+	// Determine the bytes used already
+	bytesUsed := 0
+	for _, msg := range msgs {
+		lm := len(msg)
+		bytesUsed += lm + overhead
+		metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm))
+	}
+
+	// Get any additional query broadcasts
+	queryMsgs := d.serf.queryBroadcasts.GetBroadcasts(overhead, limit-bytesUsed)
+	if queryMsgs != nil {
+		for _, m := range queryMsgs {
+			lm := len(m)
+			bytesUsed += lm + overhead
+			metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm))
+		}
+		msgs = append(msgs, queryMsgs...)
+	}
+
+	// Get any additional event broadcasts
+	eventMsgs := d.serf.eventBroadcasts.GetBroadcasts(overhead, limit-bytesUsed)
+	if eventMsgs != nil {
+		for _, m := range eventMsgs {
+			lm := len(m)
+			bytesUsed += lm + overhead
+			metrics.AddSample([]string{"serf", "msgs", "sent"}, float32(lm))
+		}
+		msgs = append(msgs, eventMsgs...)
+	}
+
+	return msgs
+}
+
+func (d *delegate) LocalState(join bool) []byte {
+	d.serf.memberLock.RLock()
+	defer d.serf.memberLock.RUnlock()
+	d.serf.eventLock.RLock()
+	defer d.serf.eventLock.RUnlock()
+
+	// Create the message to send
+	pp := messagePushPull{
+		LTime:        d.serf.clock.Time(),
+		StatusLTimes: make(map[string]LamportTime, len(d.serf.members)),
+		LeftMembers:  make([]string, 0, len(d.serf.leftMembers)),
+		EventLTime:   d.serf.eventClock.Time(),
+		Events:       d.serf.eventBuffer,
+		QueryLTime:   d.serf.queryClock.Time(),
+	}
+
+	// Add all the join LTimes
+	for name, member := range d.serf.members {
+		pp.StatusLTimes[name] = member.statusLTime
+	}
+
+	// Add all the left nodes
+	for _, member := range d.serf.leftMembers {
+		pp.LeftMembers = append(pp.LeftMembers, member.Name)
+	}
+
+	// Encode the push pull state
+	buf, err := encodeMessage(messagePushPullType, &pp)
+	if err != nil {
+		d.serf.logger.Printf("[ERR] serf: Failed to encode local state: %v", err)
+		return nil
+	}
+	return buf
+}
+
+func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) {
+	// Check the message type
+	if messageType(buf[0]) != messagePushPullType {
+		d.serf.logger.Printf("[ERR] serf: Remote state has bad type prefix: %v", buf[0])
+		return
+	}
+
+	// Attempt a decode
+	pp := messagePushPull{}
+	if err := decodeMessage(buf[1:], &pp); err != nil {
+		d.serf.logger.Printf("[ERR] serf: Failed to decode remote state: %v", err)
+		return
+	}
+
+	// Witness the Lamport clocks first.
+	// We subtract 1 since no message with that clock has been sent yet
+	if pp.LTime > 0 {
+		d.serf.clock.Witness(pp.LTime - 1)
+	}
+	if pp.EventLTime > 0 {
+		d.serf.eventClock.Witness(pp.EventLTime - 1)
+	}
+	if pp.QueryLTime > 0 {
+		d.serf.queryClock.Witness(pp.QueryLTime - 1)
+	}
+
+	// Process the left nodes first to avoid the LTimes from being increment
+	// in the wrong order
+	leftMap := make(map[string]struct{}, len(pp.LeftMembers))
+	leave := messageLeave{}
+	for _, name := range pp.LeftMembers {
+		leftMap[name] = struct{}{}
+		leave.LTime = pp.StatusLTimes[name]
+		leave.Node = name
+		d.serf.handleNodeLeaveIntent(&leave)
+	}
+
+	// Update any other LTimes
+	join := messageJoin{}
+	for name, statusLTime := range pp.StatusLTimes {
+		// Skip the left nodes
+		if _, ok := leftMap[name]; ok {
+			continue
+		}
+
+		// Create an artificial join message
+		join.LTime = statusLTime
+		join.Node = name
+		d.serf.handleNodeJoinIntent(&join)
+	}
+
+	// If we are doing a join, and eventJoinIgnore is set
+	// then we set the eventMinTime to the EventLTime. This
+	// prevents any of the incoming events from being processed
+	if isJoin && d.serf.eventJoinIgnore {
+		d.serf.eventLock.Lock()
+		if pp.EventLTime > d.serf.eventMinTime {
+			d.serf.eventMinTime = pp.EventLTime
+		}
+		d.serf.eventLock.Unlock()
+	}
+
+	// Process all the events
+	userEvent := messageUserEvent{}
+	for _, events := range pp.Events {
+		if events == nil {
+			continue
+		}
+		userEvent.LTime = events.LTime
+		for _, e := range events.Events {
+			userEvent.Name = e.Name
+			userEvent.Payload = e.Payload
+			d.serf.handleUserEvent(&userEvent)
+		}
+	}
+}

+ 213 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/delegate_test.go

@@ -0,0 +1,213 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+	"github.com/hashicorp/serf/testutil"
+	"reflect"
+	"testing"
+)
+
+func TestDelegate_impl(t *testing.T) {
+	var raw interface{}
+	raw = new(delegate)
+	if _, ok := raw.(memberlist.Delegate); !ok {
+		t.Fatal("should be an Delegate")
+	}
+}
+
+func TestDelegate_NodeMeta_Old(t *testing.T) {
+	c := testConfig()
+	c.ProtocolVersion = 2
+	c.Tags["role"] = "test"
+	d := &delegate{&Serf{config: c}}
+	meta := d.NodeMeta(32)
+
+	if !reflect.DeepEqual(meta, []byte("test")) {
+		t.Fatalf("bad meta data: %v", meta)
+	}
+
+	out := d.serf.decodeTags(meta)
+	if out["role"] != "test" {
+		t.Fatalf("bad meta data: %v", meta)
+	}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatalf("expected panic")
+		}
+	}()
+	d.NodeMeta(1)
+}
+
+func TestDelegate_NodeMeta_New(t *testing.T) {
+	c := testConfig()
+	c.ProtocolVersion = 3
+	c.Tags["role"] = "test"
+	d := &delegate{&Serf{config: c}}
+	meta := d.NodeMeta(32)
+
+	out := d.serf.decodeTags(meta)
+	if out["role"] != "test" {
+		t.Fatalf("bad meta data: %v", meta)
+	}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatalf("expected panic")
+		}
+	}()
+	d.NodeMeta(1)
+}
+
+// internals
+func TestDelegate_LocalState(t *testing.T) {
+	c1 := testConfig()
+	s1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	c2 := testConfig()
+	s2, err := Create(c2)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{c2.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	err = s1.UserEvent("test", []byte("test"), false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	_, err = s1.Query("foo", nil, nil)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// s2 can leave now
+	s2.Leave()
+
+	// Do a state dump
+	d := c1.MemberlistConfig.Delegate
+	buf := d.LocalState(false)
+
+	// Verify
+	if messageType(buf[0]) != messagePushPullType {
+		t.Fatalf("bad message type")
+	}
+
+	// Attempt a decode
+	pp := messagePushPull{}
+	if err := decodeMessage(buf[1:], &pp); err != nil {
+		t.Fatalf("decode failed %v", err)
+	}
+
+	// Verify lamport
+	if pp.LTime != s1.clock.Time() {
+		t.Fatalf("clock mismatch")
+	}
+
+	// Verify the status
+	if len(pp.StatusLTimes) != 2 {
+		t.Fatalf("missing ltimes")
+	}
+
+	if len(pp.LeftMembers) != 1 {
+		t.Fatalf("missing left members")
+	}
+
+	if pp.EventLTime != s1.eventClock.Time() {
+		t.Fatalf("clock mismatch")
+	}
+
+	if len(pp.Events) != s1.config.EventBuffer {
+		t.Fatalf("should send full event buffer")
+	}
+
+	if pp.QueryLTime != s1.queryClock.Time() {
+		t.Fatalf("clock mismatch")
+	}
+}
+
+// internals
+func TestDelegate_MergeRemoteState(t *testing.T) {
+	c1 := testConfig()
+	s1, err := Create(c1)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	// Do a state dump
+	d := c1.MemberlistConfig.Delegate
+
+	// Make a fake push pull
+	pp := messagePushPull{
+		LTime: 42,
+		StatusLTimes: map[string]LamportTime{
+			"test": 20,
+			"foo":  15,
+		},
+		LeftMembers: []string{"foo"},
+		EventLTime:  50,
+		Events: []*userEvents{
+			&userEvents{
+				LTime: 45,
+				Events: []userEvent{
+					userEvent{
+						Name:    "test",
+						Payload: nil,
+					},
+				},
+			},
+		},
+		QueryLTime: 100,
+	}
+
+	buf, err := encodeMessage(messagePushPullType, &pp)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Merge in fake state
+	d.MergeRemoteState(buf, false)
+
+	// Verify lamport
+	if s1.clock.Time() != 42 {
+		t.Fatalf("clock mismatch")
+	}
+
+	// Verify pending join for test
+	if s1.recentJoin[0].Node != "test" || s1.recentJoin[0].LTime != 20 {
+		t.Fatalf("bad recent join")
+	}
+
+	// Verify pending leave for foo
+	if s1.recentLeave[0].Node != "foo" || s1.recentLeave[0].LTime != 15 {
+		t.Fatalf("bad recent leave")
+	}
+
+	// Very event time
+	if s1.eventClock.Time() != 50 {
+		t.Fatalf("bad event clock")
+	}
+
+	if s1.eventBuffer[45] == nil {
+		t.Fatalf("missing event buffer for time")
+	}
+	if s1.eventBuffer[45].Events[0].Name != "test" {
+		t.Fatalf("missing event")
+	}
+
+	if s1.queryClock.Time() != 100 {
+		t.Fatalf("bad query clock")
+	}
+}

+ 168 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event.go

@@ -0,0 +1,168 @@
+package serf
+
+import (
+	"fmt"
+	"net"
+	"sync"
+	"time"
+)
+
+// EventType are all the types of events that may occur and be sent
+// along the Serf channel.
+type EventType int
+
+const (
+	EventMemberJoin EventType = iota
+	EventMemberLeave
+	EventMemberFailed
+	EventMemberUpdate
+	EventMemberReap
+	EventUser
+	EventQuery
+)
+
+func (t EventType) String() string {
+	switch t {
+	case EventMemberJoin:
+		return "member-join"
+	case EventMemberLeave:
+		return "member-leave"
+	case EventMemberFailed:
+		return "member-failed"
+	case EventMemberUpdate:
+		return "member-update"
+	case EventMemberReap:
+		return "member-reap"
+	case EventUser:
+		return "user"
+	case EventQuery:
+		return "query"
+	default:
+		panic(fmt.Sprintf("unknown event type: %d", t))
+	}
+}
+
+// Event is a generic interface for exposing Serf events
+// Clients will usually need to use a type switches to get
+// to a more useful type
+type Event interface {
+	EventType() EventType
+	String() string
+}
+
+// MemberEvent is the struct used for member related events
+// Because Serf coalesces events, an event may contain multiple members.
+type MemberEvent struct {
+	Type    EventType
+	Members []Member
+}
+
+func (m MemberEvent) EventType() EventType {
+	return m.Type
+}
+
+func (m MemberEvent) String() string {
+	switch m.Type {
+	case EventMemberJoin:
+		return "member-join"
+	case EventMemberLeave:
+		return "member-leave"
+	case EventMemberFailed:
+		return "member-failed"
+	case EventMemberUpdate:
+		return "member-update"
+	case EventMemberReap:
+		return "member-reap"
+	default:
+		panic(fmt.Sprintf("unknown event type: %d", m.Type))
+	}
+}
+
+// UserEvent is the struct used for events that are triggered
+// by the user and are not related to members
+type UserEvent struct {
+	LTime    LamportTime
+	Name     string
+	Payload  []byte
+	Coalesce bool
+}
+
+func (u UserEvent) EventType() EventType {
+	return EventUser
+}
+
+func (u UserEvent) String() string {
+	return fmt.Sprintf("user-event: %s", u.Name)
+}
+
+// Query is the struct used EventQuery type events
+type Query struct {
+	LTime   LamportTime
+	Name    string
+	Payload []byte
+
+	serf     *Serf
+	id       uint32    // ID is not exported, since it may change
+	addr     []byte    // Address to respond to
+	port     uint16    // Port to respond to
+	deadline time.Time // Must respond by this deadline
+	respLock sync.Mutex
+}
+
+func (q *Query) EventType() EventType {
+	return EventQuery
+}
+
+func (q *Query) String() string {
+	return fmt.Sprintf("query: %s", q.Name)
+}
+
+// Deadline returns the time by which a response must be sent
+func (q *Query) Deadline() time.Time {
+	return q.deadline
+}
+
+// Respond is used to send a response to the user query
+func (q *Query) Respond(buf []byte) error {
+	q.respLock.Lock()
+	defer q.respLock.Unlock()
+
+	// Check if we've already responded
+	if q.deadline.IsZero() {
+		return fmt.Errorf("Response already sent")
+	}
+
+	// Ensure we aren't past our response deadline
+	if time.Now().After(q.deadline) {
+		return fmt.Errorf("Response is past the deadline")
+	}
+
+	// Create response
+	resp := messageQueryResponse{
+		LTime:   q.LTime,
+		ID:      q.id,
+		From:    q.serf.config.NodeName,
+		Payload: buf,
+	}
+
+	// Format the response
+	raw, err := encodeMessage(messageQueryResponseType, &resp)
+	if err != nil {
+		return fmt.Errorf("Failed to format response: %v", err)
+	}
+
+	// Check the size limit
+	if len(raw) > QueryResponseSizeLimit {
+		return fmt.Errorf("response exceeds limit of %d bytes", QueryResponseSizeLimit)
+	}
+
+	// Send the response
+	addr := net.UDPAddr{IP: q.addr, Port: int(q.port)}
+	if err := q.serf.memberlist.SendTo(&addr, raw); err != nil {
+		return err
+	}
+
+	// Clera the deadline, response sent
+	q.deadline = time.Time{}
+	return nil
+}

+ 21 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event_delegate.go

@@ -0,0 +1,21 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+)
+
+type eventDelegate struct {
+	serf *Serf
+}
+
+func (e *eventDelegate) NotifyJoin(n *memberlist.Node) {
+	e.serf.handleNodeJoin(n)
+}
+
+func (e *eventDelegate) NotifyLeave(n *memberlist.Node) {
+	e.serf.handleNodeLeave(n)
+}
+
+func (e *eventDelegate) NotifyUpdate(n *memberlist.Node) {
+	e.serf.handleNodeUpdate(n)
+}

+ 211 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/event_test.go

@@ -0,0 +1,211 @@
+package serf
+
+import (
+	"reflect"
+	"testing"
+	"time"
+)
+
+// testEvents tests that the given node had the given sequence of events
+// on the event channel.
+func testEvents(t *testing.T, ch <-chan Event, node string, expected []EventType) {
+	actual := make([]EventType, 0, len(expected))
+
+TESTEVENTLOOP:
+	for {
+		select {
+		case r := <-ch:
+			e, ok := r.(MemberEvent)
+			if !ok {
+				continue
+			}
+
+			found := false
+			for _, m := range e.Members {
+				if m.Name == node {
+					found = true
+					break
+				}
+			}
+
+			if found {
+				actual = append(actual, e.Type)
+			}
+		case <-time.After(10 * time.Millisecond):
+			break TESTEVENTLOOP
+		}
+	}
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("expected events: %v. Got: %v", expected, actual)
+	}
+}
+
+// testUserEvents tests that the given sequence of usr events
+// on the event channel took place.
+func testUserEvents(t *testing.T, ch <-chan Event, expectedName []string, expectedPayload [][]byte) {
+	actualName := make([]string, 0, len(expectedName))
+	actualPayload := make([][]byte, 0, len(expectedPayload))
+
+TESTEVENTLOOP:
+	for {
+		select {
+		case r, ok := <-ch:
+			if !ok {
+				break TESTEVENTLOOP
+			}
+			u, ok := r.(UserEvent)
+			if !ok {
+				continue
+			}
+
+			actualName = append(actualName, u.Name)
+			actualPayload = append(actualPayload, u.Payload)
+		case <-time.After(10 * time.Millisecond):
+			break TESTEVENTLOOP
+		}
+	}
+
+	if !reflect.DeepEqual(actualName, expectedName) {
+		t.Fatalf("expected names: %v. Got: %v", expectedName, actualName)
+	}
+	if !reflect.DeepEqual(actualPayload, expectedPayload) {
+		t.Fatalf("expected payloads: %v. Got: %v", expectedPayload, actualPayload)
+	}
+
+}
+
+// testQueryEvents tests that the given sequence of queries
+// on the event channel took place.
+func testQueryEvents(t *testing.T, ch <-chan Event, expectedName []string, expectedPayload [][]byte) {
+	actualName := make([]string, 0, len(expectedName))
+	actualPayload := make([][]byte, 0, len(expectedPayload))
+
+TESTEVENTLOOP:
+	for {
+		select {
+		case r, ok := <-ch:
+			if !ok {
+				break TESTEVENTLOOP
+			}
+			q, ok := r.(*Query)
+			if !ok {
+				continue
+			}
+
+			actualName = append(actualName, q.Name)
+			actualPayload = append(actualPayload, q.Payload)
+		case <-time.After(10 * time.Millisecond):
+			break TESTEVENTLOOP
+		}
+	}
+
+	if !reflect.DeepEqual(actualName, expectedName) {
+		t.Fatalf("expected names: %v. Got: %v", expectedName, actualName)
+	}
+	if !reflect.DeepEqual(actualPayload, expectedPayload) {
+		t.Fatalf("expected payloads: %v. Got: %v", expectedPayload, actualPayload)
+	}
+
+}
+
+func TestMemberEvent(t *testing.T) {
+	me := MemberEvent{
+		Type:    EventMemberJoin,
+		Members: nil,
+	}
+	if me.EventType() != EventMemberJoin {
+		t.Fatalf("bad event type")
+	}
+	if me.String() != "member-join" {
+		t.Fatalf("bad string val")
+	}
+
+	me.Type = EventMemberLeave
+	if me.EventType() != EventMemberLeave {
+		t.Fatalf("bad event type")
+	}
+	if me.String() != "member-leave" {
+		t.Fatalf("bad string val")
+	}
+
+	me.Type = EventMemberFailed
+	if me.EventType() != EventMemberFailed {
+		t.Fatalf("bad event type")
+	}
+	if me.String() != "member-failed" {
+		t.Fatalf("bad string val")
+	}
+
+	me.Type = EventMemberUpdate
+	if me.EventType() != EventMemberUpdate {
+		t.Fatalf("bad event type")
+	}
+	if me.String() != "member-update" {
+		t.Fatalf("bad string val")
+	}
+
+	me.Type = EventMemberReap
+	if me.EventType() != EventMemberReap {
+		t.Fatalf("bad event type")
+	}
+	if me.String() != "member-reap" {
+		t.Fatalf("bad string val")
+	}
+
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatalf("expected panic")
+		}
+	}()
+	me.Type = EventUser
+	me.String()
+}
+
+func TestUserEvent(t *testing.T) {
+	ue := UserEvent{
+		Name:    "test",
+		Payload: []byte("foobar"),
+	}
+	if ue.EventType() != EventUser {
+		t.Fatalf("bad event type")
+	}
+	if ue.String() != "user-event: test" {
+		t.Fatalf("bad string val")
+	}
+}
+
+func TestQuery(t *testing.T) {
+	q := Query{
+		LTime:   42,
+		Name:    "update",
+		Payload: []byte("abcd1234"),
+	}
+	if q.EventType() != EventQuery {
+		t.Fatalf("Bad")
+	}
+	if q.String() != "query: update" {
+		t.Fatalf("bad: %v", q.String())
+	}
+}
+
+func TestEventType_String(t *testing.T) {
+	events := []EventType{EventMemberJoin, EventMemberLeave, EventMemberFailed,
+		EventMemberUpdate, EventMemberReap, EventUser, EventQuery}
+	expect := []string{"member-join", "member-leave", "member-failed",
+		"member-update", "member-reap", "user", "query"}
+
+	for idx, event := range events {
+		if event.String() != expect[idx] {
+			t.Fatalf("expect %v got %v", expect[idx], event.String())
+		}
+	}
+
+	other := EventType(100)
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatalf("expected panic")
+		}
+	}()
+	other.String()
+}

+ 312 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/internal_query.go

@@ -0,0 +1,312 @@
+package serf
+
+import (
+	"encoding/base64"
+	"log"
+	"strings"
+)
+
+const (
+	// This is the prefix we use for queries that are internal to Serf.
+	// They are handled internally, and not forwarded to a client.
+	InternalQueryPrefix = "_serf_"
+
+	// pingQuery is run to check for reachability
+	pingQuery = "ping"
+
+	// conflictQuery is run to resolve a name conflict
+	conflictQuery = "conflict"
+
+	// installKeyQuery is used to install a new key
+	installKeyQuery = "install-key"
+
+	// useKeyQuery is used to change the primary encryption key
+	useKeyQuery = "use-key"
+
+	// removeKeyQuery is used to remove a key from the keyring
+	removeKeyQuery = "remove-key"
+
+	// listKeysQuery is used to list all known keys in the cluster
+	listKeysQuery = "list-keys"
+)
+
+// internalQueryName is used to generate a query name for an internal query
+func internalQueryName(name string) string {
+	return InternalQueryPrefix + name
+}
+
+// serfQueries is used to listen for queries that start with
+// _serf and respond to them as appropriate.
+type serfQueries struct {
+	inCh       chan Event
+	logger     *log.Logger
+	outCh      chan<- Event
+	serf       *Serf
+	shutdownCh <-chan struct{}
+}
+
+// nodeKeyResponse is used to store the result from an individual node while
+// replying to key modification queries
+type nodeKeyResponse struct {
+	// Result indicates true/false if there were errors or not
+	Result bool
+
+	// Message contains error messages or other information
+	Message string
+
+	// Keys is used in listing queries to relay a list of installed keys
+	Keys []string
+}
+
+// newSerfQueries is used to create a new serfQueries. We return an event
+// channel that is ingested and forwarded to an outCh. Any Queries that
+// have the InternalQueryPrefix are handled instead of forwarded.
+func newSerfQueries(serf *Serf, logger *log.Logger, outCh chan<- Event, shutdownCh <-chan struct{}) (chan<- Event, error) {
+	inCh := make(chan Event, 1024)
+	q := &serfQueries{
+		inCh:       inCh,
+		logger:     logger,
+		outCh:      outCh,
+		serf:       serf,
+		shutdownCh: shutdownCh,
+	}
+	go q.stream()
+	return inCh, nil
+}
+
+// stream is a long running routine to ingest the event stream
+func (s *serfQueries) stream() {
+	for {
+		select {
+		case e := <-s.inCh:
+			// Check if this is a query we should process
+			if q, ok := e.(*Query); ok && strings.HasPrefix(q.Name, InternalQueryPrefix) {
+				go s.handleQuery(q)
+
+			} else if s.outCh != nil {
+				s.outCh <- e
+			}
+
+		case <-s.shutdownCh:
+			return
+		}
+	}
+}
+
+// handleQuery is invoked when we get an internal query
+func (s *serfQueries) handleQuery(q *Query) {
+	// Get the queryName after the initial prefix
+	queryName := q.Name[len(InternalQueryPrefix):]
+	switch queryName {
+	case pingQuery:
+		// Nothing to do, we will ack the query
+	case conflictQuery:
+		s.handleConflict(q)
+	case installKeyQuery:
+		s.handleInstallKey(q)
+	case useKeyQuery:
+		s.handleUseKey(q)
+	case removeKeyQuery:
+		s.handleRemoveKey(q)
+	case listKeysQuery:
+		s.handleListKeys(q)
+	default:
+		s.logger.Printf("[WARN] serf: Unhandled internal query '%s'", queryName)
+	}
+}
+
+// handleConflict is invoked when we get a query that is attempting to
+// disambiguate a name conflict. They payload is a node name, and the response
+// should the address we believe that node is at, if any.
+func (s *serfQueries) handleConflict(q *Query) {
+	// The target node name is the payload
+	node := string(q.Payload)
+
+	// Do not respond to the query if it is about us
+	if node == s.serf.config.NodeName {
+		return
+	}
+	s.logger.Printf("[DEBUG] serf: Got conflict resolution query for '%s'", node)
+
+	// Look for the member info
+	var out *Member
+	s.serf.memberLock.Lock()
+	if member, ok := s.serf.members[node]; ok {
+		out = &member.Member
+	}
+	s.serf.memberLock.Unlock()
+
+	// Encode the response
+	buf, err := encodeMessage(messageConflictResponseType, out)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to encode conflict query response: %v", err)
+		return
+	}
+
+	// Send our answer
+	if err := q.Respond(buf); err != nil {
+		s.logger.Printf("[ERR] serf: Failed to respond to conflict query: %v", err)
+	}
+}
+
+// sendKeyResponse handles responding to key-related queries.
+func (s *serfQueries) sendKeyResponse(q *Query, resp *nodeKeyResponse) {
+	buf, err := encodeMessage(messageKeyResponseType, resp)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to encode key response: %v", err)
+		return
+	}
+
+	if err := q.Respond(buf); err != nil {
+		s.logger.Printf("[ERR] serf: Failed to respond to key query: %v", err)
+		return
+	}
+}
+
+// handleInstallKey is invoked whenever a new encryption key is received from
+// another member in the cluster, and handles the process of installing it onto
+// the memberlist keyring. This type of query may fail if the provided key does
+// not fit the constraints that memberlist enforces. If the query fails, the
+// response will contain the error message so that it may be relayed.
+func (s *serfQueries) handleInstallKey(q *Query) {
+	response := nodeKeyResponse{Result: false}
+	keyring := s.serf.config.MemberlistConfig.Keyring
+	req := keyRequest{}
+
+	err := decodeMessage(q.Payload[1:], &req)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err)
+		goto SEND
+	}
+
+	if !s.serf.EncryptionEnabled() {
+		response.Message = "No keyring to modify (encryption not enabled)"
+		s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)")
+		goto SEND
+	}
+
+	s.logger.Printf("[INFO] serf: Received install-key query")
+	if err := keyring.AddKey(req.Key); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to install key: %s", err)
+		goto SEND
+	}
+
+	if err := s.serf.writeKeyringFile(); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err)
+		goto SEND
+	}
+
+	response.Result = true
+
+SEND:
+	s.sendKeyResponse(q, &response)
+}
+
+// handleUseKey is invoked whenever a query is received to mark a different key
+// in the internal keyring as the primary key. This type of query may fail due
+// to operator error (requested key not in ring), and thus sends error messages
+// back in the response.
+func (s *serfQueries) handleUseKey(q *Query) {
+	response := nodeKeyResponse{Result: false}
+	keyring := s.serf.config.MemberlistConfig.Keyring
+	req := keyRequest{}
+
+	err := decodeMessage(q.Payload[1:], &req)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err)
+		goto SEND
+	}
+
+	if !s.serf.EncryptionEnabled() {
+		response.Message = "No keyring to modify (encryption not enabled)"
+		s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)")
+		goto SEND
+	}
+
+	s.logger.Printf("[INFO] serf: Received use-key query")
+	if err := keyring.UseKey(req.Key); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to change primary key: %s", err)
+		goto SEND
+	}
+
+	if err := s.serf.writeKeyringFile(); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err)
+		goto SEND
+	}
+
+	response.Result = true
+
+SEND:
+	s.sendKeyResponse(q, &response)
+}
+
+// handleRemoveKey is invoked when a query is received to remove a particular
+// key from the keyring. This type of query can fail if the key requested for
+// deletion is currently the primary key in the keyring, so therefore it will
+// reply to the query with any relevant errors from the operation.
+func (s *serfQueries) handleRemoveKey(q *Query) {
+	response := nodeKeyResponse{Result: false}
+	keyring := s.serf.config.MemberlistConfig.Keyring
+	req := keyRequest{}
+
+	err := decodeMessage(q.Payload[1:], &req)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to decode key request: %v", err)
+		goto SEND
+	}
+
+	if !s.serf.EncryptionEnabled() {
+		response.Message = "No keyring to modify (encryption not enabled)"
+		s.logger.Printf("[ERR] serf: No keyring to modify (encryption not enabled)")
+		goto SEND
+	}
+
+	s.logger.Printf("[INFO] serf: Received remove-key query")
+	if err := keyring.RemoveKey(req.Key); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to remove key: %s", err)
+		goto SEND
+	}
+
+	if err := s.serf.writeKeyringFile(); err != nil {
+		response.Message = err.Error()
+		s.logger.Printf("[ERR] serf: Failed to write keyring file: %s", err)
+		goto SEND
+	}
+
+	response.Result = true
+
+SEND:
+	s.sendKeyResponse(q, &response)
+}
+
+// handleListKeys is invoked when a query is received to return a list of all
+// installed keys the Serf instance knows of. For performance, the keys are
+// encoded to base64 on each of the members to remove this burden from the
+// node asking for the results.
+func (s *serfQueries) handleListKeys(q *Query) {
+	response := nodeKeyResponse{Result: false}
+	keyring := s.serf.config.MemberlistConfig.Keyring
+
+	if !s.serf.EncryptionEnabled() {
+		response.Message = "Keyring is empty (encryption not enabled)"
+		s.logger.Printf("[ERR] serf: Keyring is empty (encryption not enabled)")
+		goto SEND
+	}
+
+	s.logger.Printf("[INFO] serf: Received list-keys query")
+	for _, keyBytes := range keyring.GetKeys() {
+		// Encode the keys before sending the response. This should help take
+		// some the burden of doing this off of the asking member.
+		key := base64.StdEncoding.EncodeToString(keyBytes)
+		response.Keys = append(response.Keys, key)
+	}
+	response.Result = true
+
+SEND:
+	s.sendKeyResponse(q, &response)
+}

+ 89 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/internal_query_test.go

@@ -0,0 +1,89 @@
+package serf
+
+import (
+	"log"
+	"os"
+	"testing"
+	"time"
+)
+
+func TestInternalQueryName(t *testing.T) {
+	name := internalQueryName(conflictQuery)
+	if name != "_serf_conflict" {
+		t.Fatalf("bad: %v", name)
+	}
+}
+
+func TestSerfQueries_Passthrough(t *testing.T) {
+	serf := &Serf{}
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	outCh := make(chan Event, 4)
+	shutdown := make(chan struct{})
+	defer close(shutdown)
+	eventCh, err := newSerfQueries(serf, logger, outCh, shutdown)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Push a user event
+	eventCh <- UserEvent{LTime: 42, Name: "foo"}
+
+	// Push a query
+	eventCh <- &Query{LTime: 42, Name: "foo"}
+
+	// Push a query
+	eventCh <- MemberEvent{Type: EventMemberJoin}
+
+	// Should get passed through
+	for i := 0; i < 3; i++ {
+		select {
+		case <-outCh:
+		case <-time.After(100 * time.Millisecond):
+			t.Fatalf("time out")
+		}
+	}
+}
+
+func TestSerfQueries_Ping(t *testing.T) {
+	serf := &Serf{}
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	outCh := make(chan Event, 4)
+	shutdown := make(chan struct{})
+	defer close(shutdown)
+	eventCh, err := newSerfQueries(serf, logger, outCh, shutdown)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Send a ping
+	eventCh <- &Query{LTime: 42, Name: "_serf_ping"}
+
+	// Should not get passed through
+	select {
+	case <-outCh:
+		t.Fatalf("Should not passthrough query!")
+	case <-time.After(50 * time.Millisecond):
+	}
+}
+
+func TestSerfQueries_Conflict_SameName(t *testing.T) {
+	serf := &Serf{config: &Config{NodeName: "foo"}}
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	outCh := make(chan Event, 4)
+	shutdown := make(chan struct{})
+	defer close(shutdown)
+	eventCh, err := newSerfQueries(serf, logger, outCh, shutdown)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Query for our own name
+	eventCh <- &Query{Name: "_serf_conflict", Payload: []byte("foo")}
+
+	// Should not passthrough OR respond
+	select {
+	case <-outCh:
+		t.Fatalf("Should not passthrough query!")
+	case <-time.After(50 * time.Millisecond):
+	}
+}

+ 166 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/keymanager.go

@@ -0,0 +1,166 @@
+package serf
+
+import (
+	"encoding/base64"
+	"fmt"
+	"sync"
+)
+
+// KeyManager encapsulates all functionality within Serf for handling
+// encryption keyring changes across a cluster.
+type KeyManager struct {
+	serf *Serf
+
+	// Lock to protect read and write operations
+	l sync.RWMutex
+}
+
+// keyRequest is used to contain input parameters which get broadcasted to all
+// nodes as part of a key query operation.
+type keyRequest struct {
+	Key []byte
+}
+
+// KeyResponse is used to relay a query for a list of all keys in use.
+type KeyResponse struct {
+	Messages map[string]string // Map of node name to response message
+	NumNodes int               // Total nodes memberlist knows of
+	NumResp  int               // Total responses received
+	NumErr   int               // Total errors from request
+
+	// Keys is a mapping of the base64-encoded value of the key bytes to the
+	// number of nodes that have the key installed.
+	Keys map[string]int
+}
+
+// streamKeyResp takes care of reading responses from a channel and composing
+// them into a KeyResponse. It will update a KeyResponse *in place* and
+// therefore has nothing to return.
+func (k *KeyManager) streamKeyResp(resp *KeyResponse, ch <-chan NodeResponse) {
+	for r := range ch {
+		var nodeResponse nodeKeyResponse
+
+		resp.NumResp++
+
+		// Decode the response
+		if len(r.Payload) < 1 || messageType(r.Payload[0]) != messageKeyResponseType {
+			resp.Messages[r.From] = fmt.Sprintf(
+				"Invalid key query response type: %v", r.Payload)
+			resp.NumErr++
+			goto NEXT
+		}
+		if err := decodeMessage(r.Payload[1:], &nodeResponse); err != nil {
+			resp.Messages[r.From] = fmt.Sprintf(
+				"Failed to decode key query response: %v", r.Payload)
+			resp.NumErr++
+			goto NEXT
+		}
+
+		if !nodeResponse.Result {
+			resp.Messages[r.From] = nodeResponse.Message
+			resp.NumErr++
+		}
+
+		// Currently only used for key list queries, this adds keys to a counter
+		// and increments them for each node response which contains them.
+		for _, key := range nodeResponse.Keys {
+			if _, ok := resp.Keys[key]; !ok {
+				resp.Keys[key] = 1
+			} else {
+				resp.Keys[key]++
+			}
+		}
+
+	NEXT:
+		// Return early if all nodes have responded. This allows us to avoid
+		// waiting for the full timeout when there is nothing left to do.
+		if resp.NumResp == resp.NumNodes {
+			return
+		}
+	}
+}
+
+// handleKeyRequest performs query broadcasting to all members for any type of
+// key operation and manages gathering responses and packing them up into a
+// KeyResponse for uniform response handling.
+func (k *KeyManager) handleKeyRequest(key, query string) (*KeyResponse, error) {
+	resp := &KeyResponse{
+		Messages: make(map[string]string),
+		Keys:     make(map[string]int),
+	}
+	qName := internalQueryName(query)
+
+	// Decode the new key into raw bytes
+	rawKey, err := base64.StdEncoding.DecodeString(key)
+	if err != nil {
+		return resp, err
+	}
+
+	// Encode the query request
+	req, err := encodeMessage(messageKeyRequestType, keyRequest{Key: rawKey})
+	if err != nil {
+		return resp, err
+	}
+
+	qParam := k.serf.DefaultQueryParams()
+	queryResp, err := k.serf.Query(qName, req, qParam)
+	if err != nil {
+		return resp, err
+	}
+
+	// Handle the response stream and populate the KeyResponse
+	resp.NumNodes = k.serf.memberlist.NumMembers()
+	k.streamKeyResp(resp, queryResp.respCh)
+
+	// Check the response for any reported failure conditions
+	if resp.NumErr != 0 {
+		return resp, fmt.Errorf("%d/%d nodes reported failure", resp.NumErr, resp.NumNodes)
+	}
+	if resp.NumResp != resp.NumNodes {
+		return resp, fmt.Errorf("%d/%d nodes reported success", resp.NumResp, resp.NumNodes)
+	}
+
+	return resp, nil
+}
+
+// InstallKey handles broadcasting a query to all members and gathering
+// responses from each of them, returning a list of messages from each node
+// and any applicable error conditions.
+func (k *KeyManager) InstallKey(key string) (*KeyResponse, error) {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	return k.handleKeyRequest(key, installKeyQuery)
+}
+
+// UseKey handles broadcasting a primary key change to all members in the
+// cluster, and gathering any response messages. If successful, there should
+// be an empty KeyResponse returned.
+func (k *KeyManager) UseKey(key string) (*KeyResponse, error) {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	return k.handleKeyRequest(key, useKeyQuery)
+}
+
+// RemoveKey handles broadcasting a key to the cluster for removal. Each member
+// will receive this event, and if they have the key in their keyring, remove
+// it. If any errors are encountered, RemoveKey will collect and relay them.
+func (k *KeyManager) RemoveKey(key string) (*KeyResponse, error) {
+	k.l.Lock()
+	defer k.l.Unlock()
+
+	return k.handleKeyRequest(key, removeKeyQuery)
+}
+
+// ListKeys is used to collect installed keys from members in a Serf cluster
+// and return an aggregated list of all installed keys. This is useful to
+// operators to ensure that there are no lingering keys installed on any agents.
+// Since having multiple keys installed can cause performance penalties in some
+// cases, it's important to verify this information and remove unneeded keys.
+func (k *KeyManager) ListKeys() (*KeyResponse, error) {
+	k.l.RLock()
+	defer k.l.RUnlock()
+
+	return k.handleKeyRequest("", listKeysQuery)
+}

+ 272 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/keymanager_test.go

@@ -0,0 +1,272 @@
+package serf
+
+import (
+	"bytes"
+	"encoding/base64"
+	"github.com/hashicorp/memberlist"
+	"github.com/hashicorp/serf/testutil"
+	"testing"
+)
+
+func testKeyring() (*memberlist.Keyring, error) {
+	keys := []string{
+		"enjTwAFRe4IE71bOFhirzQ==",
+		"csT9mxI7aTf9ap3HLBbdmA==",
+		"noha2tVc0OyD/2LtCBoAOQ==",
+	}
+
+	keysDecoded := make([][]byte, len(keys))
+	for i, key := range keys {
+		decoded, err := base64.StdEncoding.DecodeString(key)
+		if err != nil {
+			return nil, err
+		}
+		keysDecoded[i] = decoded
+	}
+
+	return memberlist.NewKeyring(keysDecoded, keysDecoded[0])
+}
+
+func testKeyringSerf() (*Serf, error) {
+	config := testConfig()
+
+	keyring, err := testKeyring()
+	if err != nil {
+		return nil, err
+	}
+	config.MemberlistConfig.Keyring = keyring
+
+	s, err := Create(config)
+	if err != nil {
+		return nil, err
+	}
+
+	return s, nil
+}
+
+func keyExistsInRing(kr *memberlist.Keyring, key []byte) bool {
+	for _, installedKey := range kr.GetKeys() {
+		if bytes.Equal(key, installedKey) {
+			return true
+		}
+	}
+	return false
+}
+
+func TestSerf_InstallKey(t *testing.T) {
+	s1, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s2.Shutdown()
+
+	primaryKey := s1.config.MemberlistConfig.Keyring.GetPrimaryKey()
+
+	// Join s1 and s2
+	_, err = s1.Join([]string{s2.config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Begin tests
+	newKey := "l4ZkaypGLT8AsB0LBldthw=="
+	newKeyBytes, err := base64.StdEncoding.DecodeString(newKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	manager := s1.KeyManager()
+
+	// Install a new key onto the existing ring. This is a blocking call, so no
+	// need for a yield.
+	_, err = manager.InstallKey(newKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Key installation did not affect the current primary key
+	if !bytes.Equal(primaryKey, s1.config.MemberlistConfig.Keyring.GetPrimaryKey()) {
+		t.Fatal("Unexpected primary key change on s1")
+	}
+
+	if !bytes.Equal(primaryKey, s2.config.MemberlistConfig.Keyring.GetPrimaryKey()) {
+		t.Fatal("Unexpected primary key change on s2")
+	}
+
+	// New key was successfully broadcasted and installed on all members
+	if !keyExistsInRing(s1.config.MemberlistConfig.Keyring, newKeyBytes) {
+		t.Fatal("Newly-installed key not found in keyring on s1")
+	}
+
+	if !keyExistsInRing(s2.config.MemberlistConfig.Keyring, newKeyBytes) {
+		t.Fatal("Newly-installed key not found in keyring on s2")
+	}
+}
+
+func TestSerf_UseKey(t *testing.T) {
+	s1, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s2.Shutdown()
+
+	// Join s1 and s2
+	_, err = s1.Join([]string{s2.config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Begin tests
+	useKey := "csT9mxI7aTf9ap3HLBbdmA=="
+	useKeyBytes, err := base64.StdEncoding.DecodeString(useKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	manager := s1.KeyManager()
+
+	// Change the primary encryption key
+	_, err = manager.UseKey(useKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// First make sure that the primary key is what we expect it to be
+	if !bytes.Equal(useKeyBytes, s1.config.MemberlistConfig.Keyring.GetPrimaryKey()) {
+		t.Fatal("Unexpected primary key on s1")
+	}
+
+	if !bytes.Equal(useKeyBytes, s2.config.MemberlistConfig.Keyring.GetPrimaryKey()) {
+		t.Fatal("Unexpected primary key on s2")
+	}
+
+	// Make sure an error is thrown if the key doesn't exist
+	_, err = manager.UseKey("aE6AfGEvay+UJbkfxBk4SQ==")
+	if err == nil {
+		t.Fatalf("Expected error changing to non-existent primary key")
+	}
+}
+
+func TestSerf_RemoveKey(t *testing.T) {
+	s1, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s2.Shutdown()
+
+	// Join s1 and s2
+	_, err = s1.Join([]string{s2.config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Begin tests
+	removeKey := "noha2tVc0OyD/2LtCBoAOQ=="
+	removeKeyBytes, err := base64.StdEncoding.DecodeString(removeKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	manager := s1.KeyManager()
+
+	// Remove a key from the ring
+	_, err = manager.RemoveKey(removeKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Key was successfully removed from all members
+	if keyExistsInRing(s1.config.MemberlistConfig.Keyring, removeKeyBytes) {
+		t.Fatal("Key not removed from keyring on s1")
+	}
+
+	if keyExistsInRing(s2.config.MemberlistConfig.Keyring, removeKeyBytes) {
+		t.Fatal("Key not removed from keyring on s2")
+	}
+}
+
+func TestSerf_ListKeys(t *testing.T) {
+	s1, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := testKeyringSerf()
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	defer s2.Shutdown()
+
+	manager := s1.KeyManager()
+
+	initialKeyringLen := len(s1.config.MemberlistConfig.Keyring.GetKeys())
+
+	// Extra key on s2 to make sure we see it in the list
+	extraKey := "JHAxGU13qDaXhUW6jIpyog=="
+	extraKeyBytes, err := base64.StdEncoding.DecodeString(extraKey)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	s2.config.MemberlistConfig.Keyring.AddKey(extraKeyBytes)
+
+	// Join s1 and s2
+	_, err = s1.Join([]string{s2.config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	resp, err := manager.ListKeys()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Found all keys in the list
+	expected := initialKeyringLen + 1
+	if expected != len(resp.Keys) {
+		t.Fatalf("Expected %d keys in result, found %d", expected, len(resp.Keys))
+	}
+
+	found := false
+	for key, _ := range resp.Keys {
+		if key == extraKey {
+			found = true
+		}
+	}
+	if !found {
+		t.Fatalf("Did not find expected key in list: %s", extraKey)
+	}
+
+	// Number of members with extra key installed should be 1
+	for key, num := range resp.Keys {
+		if key == extraKey && num != 1 {
+			t.Fatalf("Expected 1 nodes with key %s but have %d", extraKey, num)
+		}
+	}
+}

+ 45 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/lamport.go

@@ -0,0 +1,45 @@
+package serf
+
+import (
+	"sync/atomic"
+)
+
+// LamportClock is a thread safe implementation of a lamport clock. It
+// uses efficient atomic operations for all of its functions, falling back
+// to a heavy lock only if there are enough CAS failures.
+type LamportClock struct {
+	counter uint64
+}
+
+// LamportTime is the value of a LamportClock.
+type LamportTime uint64
+
+// Time is used to return the current value of the lamport clock
+func (l *LamportClock) Time() LamportTime {
+	return LamportTime(atomic.LoadUint64(&l.counter))
+}
+
+// Increment is used to increment and return the value of the lamport clock
+func (l *LamportClock) Increment() LamportTime {
+	return LamportTime(atomic.AddUint64(&l.counter, 1))
+}
+
+// Witness is called to update our local clock if necessary after
+// witnessing a clock value received from another process
+func (l *LamportClock) Witness(v LamportTime) {
+WITNESS:
+	// If the other value is old, we do not need to do anything
+	cur := atomic.LoadUint64(&l.counter)
+	other := uint64(v)
+	if other < cur {
+		return
+	}
+
+	// Ensure that our local clock is at least one ahead.
+	if !atomic.CompareAndSwapUint64(&l.counter, cur, other+1) {
+		// The CAS failed, so we just retry. Eventually our CAS should
+		// succeed or a future witness will pass us by and our witness
+		// will end.
+		goto WITNESS
+	}
+}

+ 39 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/lamport_test.go

@@ -0,0 +1,39 @@
+package serf
+
+import (
+	"testing"
+)
+
+func TestLamportClock(t *testing.T) {
+	l := &LamportClock{}
+
+	if l.Time() != 0 {
+		t.Fatalf("bad time value")
+	}
+
+	if l.Increment() != 1 {
+		t.Fatalf("bad time value")
+	}
+
+	if l.Time() != 1 {
+		t.Fatalf("bad time value")
+	}
+
+	l.Witness(41)
+
+	if l.Time() != 42 {
+		t.Fatalf("bad time value")
+	}
+
+	l.Witness(41)
+
+	if l.Time() != 42 {
+		t.Fatalf("bad time value")
+	}
+
+	l.Witness(30)
+
+	if l.Time() != 42 {
+		t.Fatalf("bad time value")
+	}
+}

+ 35 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/merge_delegate.go

@@ -0,0 +1,35 @@
+package serf
+
+import (
+	"net"
+
+	"github.com/hashicorp/memberlist"
+)
+
+type MergeDelegate interface {
+	NotifyMerge([]*Member) (cancel bool)
+}
+
+type mergeDelegate struct {
+	serf *Serf
+}
+
+func (m *mergeDelegate) NotifyMerge(nodes []*memberlist.Node) (cancel bool) {
+	members := make([]*Member, len(nodes))
+	for idx, n := range nodes {
+		members[idx] = &Member{
+			Name:        n.Name,
+			Addr:        net.IP(n.Addr),
+			Port:        n.Port,
+			Tags:        m.serf.decodeTags(n.Meta),
+			Status:      StatusNone,
+			ProtocolMin: n.PMin,
+			ProtocolMax: n.PMax,
+			ProtocolCur: n.PCur,
+			DelegateMin: n.DMin,
+			DelegateMax: n.DMax,
+			DelegateCur: n.DCur,
+		}
+	}
+	return m.serf.config.Merge.NotifyMerge(members)
+}

+ 147 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/messages.go

@@ -0,0 +1,147 @@
+package serf
+
+import (
+	"bytes"
+	"github.com/hashicorp/go-msgpack/codec"
+	"time"
+)
+
+// messageType are the types of gossip messages Serf will send along
+// memberlist.
+type messageType uint8
+
+const (
+	messageLeaveType messageType = iota
+	messageJoinType
+	messagePushPullType
+	messageUserEventType
+	messageQueryType
+	messageQueryResponseType
+	messageConflictResponseType
+	messageKeyRequestType
+	messageKeyResponseType
+)
+
+const (
+	// Ack flag is used to force receiver to send an ack back
+	queryFlagAck uint32 = 1 << iota
+
+	// NoBroadcast is used to prevent re-broadcast of a query.
+	// this can be used to selectively send queries to individual members
+	queryFlagNoBroadcast
+)
+
+// filterType is used with a queryFilter to specify the type of
+// filter we are sending
+type filterType uint8
+
+const (
+	filterNodeType filterType = iota
+	filterTagType
+)
+
+// messageJoin is the message broadcasted after we join to
+// associated the node with a lamport clock
+type messageJoin struct {
+	LTime LamportTime
+	Node  string
+}
+
+// messageLeave is the message broadcasted to signal the intentional to
+// leave.
+type messageLeave struct {
+	LTime LamportTime
+	Node  string
+}
+
+// messagePushPullType is used when doing a state exchange. This
+// is a relatively large message, but is sent infrequently
+type messagePushPull struct {
+	LTime        LamportTime            // Current node lamport time
+	StatusLTimes map[string]LamportTime // Maps the node to its status time
+	LeftMembers  []string               // List of left nodes
+	EventLTime   LamportTime            // Lamport time for event clock
+	Events       []*userEvents          // Recent events
+	QueryLTime   LamportTime            // Lamport time for query clock
+}
+
+// messageUserEvent is used for user-generated events
+type messageUserEvent struct {
+	LTime   LamportTime
+	Name    string
+	Payload []byte
+	CC      bool // "Can Coalesce". Zero value is compatible with Serf 0.1
+}
+
+// messageQuery is used for query events
+type messageQuery struct {
+	LTime   LamportTime   // Event lamport time
+	ID      uint32        // Query ID, randomly generated
+	Addr    []byte        // Source address, used for a direct reply
+	Port    uint16        // Source port, used for a direct reply
+	Filters [][]byte      // Potential query filters
+	Flags   uint32        // Used to provide various flags
+	Timeout time.Duration // Maximum time between delivery and response
+	Name    string        // Query name
+	Payload []byte        // Query payload
+}
+
+// Ack checks if the ack flag is set
+func (m *messageQuery) Ack() bool {
+	return (m.Flags & queryFlagAck) != 0
+}
+
+// NoBroadcast checks if the no broadcast flag is set
+func (m *messageQuery) NoBroadcast() bool {
+	return (m.Flags & queryFlagNoBroadcast) != 0
+}
+
+// filterNode is used with the filterNodeType, and is a list
+// of node names
+type filterNode []string
+
+// filterTag is used with the filterTagType and is a regular
+// expression to apply to a tag
+type filterTag struct {
+	Tag  string
+	Expr string
+}
+
+// messageQueryResponse is used to respond to a query
+type messageQueryResponse struct {
+	LTime   LamportTime // Event lamport time
+	ID      uint32      // Query ID
+	From    string      // Node name
+	Flags   uint32      // Used to provide various flags
+	Payload []byte      // Optional response payload
+}
+
+// Ack checks if the ack flag is set
+func (m *messageQueryResponse) Ack() bool {
+	return (m.Flags & queryFlagAck) != 0
+}
+
+func decodeMessage(buf []byte, out interface{}) error {
+	var handle codec.MsgpackHandle
+	return codec.NewDecoder(bytes.NewReader(buf), &handle).Decode(out)
+}
+
+func encodeMessage(t messageType, msg interface{}) ([]byte, error) {
+	buf := bytes.NewBuffer(nil)
+	buf.WriteByte(uint8(t))
+
+	handle := codec.MsgpackHandle{}
+	encoder := codec.NewEncoder(buf, &handle)
+	err := encoder.Encode(msg)
+	return buf.Bytes(), err
+}
+
+func encodeFilter(f filterType, filt interface{}) ([]byte, error) {
+	buf := bytes.NewBuffer(nil)
+	buf.WriteByte(uint8(f))
+
+	handle := codec.MsgpackHandle{}
+	encoder := codec.NewEncoder(buf, &handle)
+	err := encoder.Encode(filt)
+	return buf.Bytes(), err
+}

+ 58 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/messages_test.go

@@ -0,0 +1,58 @@
+package serf
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestQueryFlags(t *testing.T) {
+	if queryFlagAck != 1 {
+		t.Fatalf("Bad: %v", queryFlagAck)
+	}
+	if queryFlagNoBroadcast != 2 {
+		t.Fatalf("Bad: %v", queryFlagNoBroadcast)
+	}
+}
+
+func TestEncodeMessage(t *testing.T) {
+	in := &messageLeave{Node: "foo"}
+	raw, err := encodeMessage(messageLeaveType, in)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if raw[0] != byte(messageLeaveType) {
+		t.Fatal("should have type header")
+	}
+
+	var out messageLeave
+	if err := decodeMessage(raw[1:], &out); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(in, &out) {
+		t.Fatalf("mis-match")
+	}
+}
+
+func TestEncodeFilter(t *testing.T) {
+	nodes := []string{"foo", "bar"}
+
+	raw, err := encodeFilter(filterNodeType, nodes)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if raw[0] != byte(filterNodeType) {
+		t.Fatal("should have type header")
+	}
+
+	var out []string
+	if err := decodeMessage(raw[1:], &out); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !reflect.DeepEqual(nodes, out) {
+		t.Fatalf("mis-match")
+	}
+}

+ 210 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/query.go

@@ -0,0 +1,210 @@
+package serf
+
+import (
+	"math"
+	"regexp"
+	"sync"
+	"time"
+)
+
+// QueryParam is provided to Query() to configure the parameters of the
+// query. If not provided, sane defaults will be used.
+type QueryParam struct {
+	// If provided, we restrict the nodes that should respond to those
+	// with names in this list
+	FilterNodes []string
+
+	// FilterTags maps a tag name to a regular expression that is applied
+	// to restrict the nodes that should respond
+	FilterTags map[string]string
+
+	// If true, we are requesting an delivery acknowledgement from
+	// every node that meets the filter requirement. This means nodes
+	// the receive the message but do not pass the filters, will not
+	// send an ack.
+	RequestAck bool
+
+	// The timeout limits how long the query is left open. If not provided,
+	// then a default timeout is used based on the configuration of Serf
+	Timeout time.Duration
+}
+
+// DefaultQueryTimeout returns the default timeout value for a query
+// Computed as GossipInterval * QueryTimeoutMult * log(N+1)
+func (s *Serf) DefaultQueryTimeout() time.Duration {
+	n := s.memberlist.NumMembers()
+	timeout := s.config.MemberlistConfig.GossipInterval
+	timeout *= time.Duration(s.config.QueryTimeoutMult)
+	timeout *= time.Duration(math.Ceil(math.Log10(float64(n + 1))))
+	return timeout
+}
+
+// DefaultQueryParam is used to return the default query parameters
+func (s *Serf) DefaultQueryParams() *QueryParam {
+	return &QueryParam{
+		FilterNodes: nil,
+		FilterTags:  nil,
+		RequestAck:  false,
+		Timeout:     s.DefaultQueryTimeout(),
+	}
+}
+
+// encodeFilters is used to convert the filters into the wire format
+func (q *QueryParam) encodeFilters() ([][]byte, error) {
+	var filters [][]byte
+
+	// Add the node filter
+	if len(q.FilterNodes) > 0 {
+		if buf, err := encodeFilter(filterNodeType, q.FilterNodes); err != nil {
+			return nil, err
+		} else {
+			filters = append(filters, buf)
+		}
+	}
+
+	// Add the tag filters
+	for tag, expr := range q.FilterTags {
+		filt := filterTag{tag, expr}
+		if buf, err := encodeFilter(filterTagType, &filt); err != nil {
+			return nil, err
+		} else {
+			filters = append(filters, buf)
+		}
+	}
+
+	return filters, nil
+}
+
+// QueryResponse is returned for each new Query. It is used to collect
+// Ack's as well as responses and to provide those back to a client.
+type QueryResponse struct {
+	// ackCh is used to send the name of a node for which we've received an ack
+	ackCh chan string
+
+	// deadline is the query end time (start + query timeout)
+	deadline time.Time
+
+	// Query ID
+	id uint32
+
+	// Stores the LTime of the query
+	lTime LamportTime
+
+	// respCh is used to send a response from a node
+	respCh chan NodeResponse
+
+	closed    bool
+	closeLock sync.Mutex
+}
+
+// newQueryResponse is used to construct a new query response
+func newQueryResponse(n int, q *messageQuery) *QueryResponse {
+	resp := &QueryResponse{
+		deadline: time.Now().Add(q.Timeout),
+		id:       q.ID,
+		lTime:    q.LTime,
+		respCh:   make(chan NodeResponse, n),
+	}
+	if q.Ack() {
+		resp.ackCh = make(chan string, n)
+	}
+	return resp
+}
+
+// Close is used to close the query, which will close the underlying
+// channels and prevent further deliveries
+func (r *QueryResponse) Close() {
+	r.closeLock.Lock()
+	defer r.closeLock.Unlock()
+	if r.closed {
+		return
+	}
+	r.closed = true
+	if r.ackCh != nil {
+		close(r.ackCh)
+	}
+	if r.respCh != nil {
+		close(r.respCh)
+	}
+}
+
+// Deadline returns the ending deadline of the query
+func (r *QueryResponse) Deadline() time.Time {
+	return r.deadline
+}
+
+// Finished returns if the query is finished running
+func (r *QueryResponse) Finished() bool {
+	return r.closed || time.Now().After(r.deadline)
+}
+
+// AckCh returns a channel that can be used to listen for acks
+// Channel will be closed when the query is finished. This is nil,
+// if the query did not specify RequestAck.
+func (r *QueryResponse) AckCh() <-chan string {
+	return r.ackCh
+}
+
+// ResponseCh returns a channel that can be used to listen for responses.
+// Channel will be closed when the query is finished.
+func (r *QueryResponse) ResponseCh() <-chan NodeResponse {
+	return r.respCh
+}
+
+// NodeResponse is used to represent a single response from a node
+type NodeResponse struct {
+	From    string
+	Payload []byte
+}
+
+// shouldProcessQuery checks if a query should be proceeded given
+// a set of filers.
+func (s *Serf) shouldProcessQuery(filters [][]byte) bool {
+	for _, filter := range filters {
+		switch filterType(filter[0]) {
+		case filterNodeType:
+			// Decode the filter
+			var nodes filterNode
+			if err := decodeMessage(filter[1:], &nodes); err != nil {
+				s.logger.Printf("[WARN] serf: failed to decode filterNodeType: %v", err)
+				return false
+			}
+
+			// Check if we are being targeted
+			found := false
+			for _, n := range nodes {
+				if n == s.config.NodeName {
+					found = true
+					break
+				}
+			}
+			if !found {
+				return false
+			}
+
+		case filterTagType:
+			// Decode the filter
+			var filt filterTag
+			if err := decodeMessage(filter[1:], &filt); err != nil {
+				s.logger.Printf("[WARN] serf: failed to decode filterTagType: %v", err)
+				return false
+			}
+
+			// Check if we match this regex
+			tags := s.config.Tags
+			matched, err := regexp.MatchString(filt.Expr, tags[filt.Tag])
+			if err != nil {
+				s.logger.Printf("[WARN] serf: failed to compile filter regex (%s): %v", filt.Expr, err)
+				return false
+			}
+			if !matched {
+				return false
+			}
+
+		default:
+			s.logger.Printf("[WARN] serf: query has unrecognized filter type: %d", filter[0])
+			return false
+		}
+	}
+	return true
+}

+ 138 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/query_test.go

@@ -0,0 +1,138 @@
+package serf
+
+import (
+	"testing"
+	"time"
+)
+
+func TestDefaultQuery(t *testing.T) {
+	s1Config := testConfig()
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	timeout := s1.DefaultQueryTimeout()
+	if timeout != s1Config.MemberlistConfig.GossipInterval*time.Duration(s1Config.QueryTimeoutMult) {
+		t.Fatalf("bad: %v", timeout)
+	}
+
+	params := s1.DefaultQueryParams()
+	if params.FilterNodes != nil {
+		t.Fatalf("bad: %v", *params)
+	}
+	if params.FilterTags != nil {
+		t.Fatalf("bad: %v", *params)
+	}
+	if params.RequestAck {
+		t.Fatalf("bad: %v", *params)
+	}
+	if params.Timeout != timeout {
+		t.Fatalf("bad: %v", *params)
+	}
+}
+
+func TestQueryParams_EncodeFilters(t *testing.T) {
+	q := &QueryParam{
+		FilterNodes: []string{"foo", "bar"},
+		FilterTags: map[string]string{
+			"role":       "^web",
+			"datacenter": "aws$",
+		},
+	}
+
+	filters, err := q.encodeFilters()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if len(filters) != 3 {
+		t.Fatalf("bad: %v", filters)
+	}
+
+	nodeFilt := filters[0]
+	if filterType(nodeFilt[0]) != filterNodeType {
+		t.Fatalf("bad: %v", nodeFilt)
+	}
+
+	tagFilt := filters[1]
+	if filterType(tagFilt[0]) != filterTagType {
+		t.Fatalf("bad: %v", tagFilt)
+	}
+
+	tagFilt = filters[2]
+	if filterType(tagFilt[0]) != filterTagType {
+		t.Fatalf("bad: %v", tagFilt)
+	}
+}
+
+func TestSerf_ShouldProcess(t *testing.T) {
+	s1Config := testConfig()
+	s1Config.NodeName = "zip"
+	s1Config.Tags = map[string]string{
+		"role":       "webserver",
+		"datacenter": "east-aws",
+	}
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	// Try a matching query
+	q := &QueryParam{
+		FilterNodes: []string{"foo", "bar", "zip"},
+		FilterTags: map[string]string{
+			"role":       "^web",
+			"datacenter": "aws$",
+		},
+	}
+	filters, err := q.encodeFilters()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if !s1.shouldProcessQuery(filters) {
+		t.Fatalf("expected true")
+	}
+
+	// Omit node
+	q = &QueryParam{
+		FilterNodes: []string{"foo", "bar"},
+	}
+	filters, err = q.encodeFilters()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if s1.shouldProcessQuery(filters) {
+		t.Fatalf("expected false")
+	}
+
+	// Filter on missing tag
+	q = &QueryParam{
+		FilterTags: map[string]string{
+			"other": "cool",
+		},
+	}
+	filters, err = q.encodeFilters()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if s1.shouldProcessQuery(filters) {
+		t.Fatalf("expected false")
+	}
+
+	// Bad tag
+	q = &QueryParam{
+		FilterTags: map[string]string{
+			"role": "db",
+		},
+	}
+	filters, err = q.encodeFilters()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if s1.shouldProcessQuery(filters) {
+		t.Fatalf("expected false")
+	}
+}

+ 1598 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf.go

@@ -0,0 +1,1598 @@
+package serf
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"net"
+	"strconv"
+	"sync"
+	"time"
+
+	"github.com/armon/go-metrics"
+	"github.com/hashicorp/go-msgpack/codec"
+	"github.com/hashicorp/memberlist"
+)
+
+// These are the protocol versions that Serf can _understand_. These are
+// Serf-level protocol versions that are passed down as the delegate
+// version to memberlist below.
+const (
+	ProtocolVersionMin uint8 = 2
+	ProtocolVersionMax       = 4
+)
+
+const (
+	// Used to detect if the meta data is tags
+	// or if it is a raw role
+	tagMagicByte uint8 = 255
+)
+
+var (
+	// FeatureNotSupported is returned if a feature cannot be used
+	// due to an older protocol version being used.
+	FeatureNotSupported = fmt.Errorf("Feature not supported")
+)
+
+func init() {
+	// Seed the random number generator
+	rand.Seed(time.Now().UnixNano())
+}
+
+// Serf is a single node that is part of a single cluster that gets
+// events about joins/leaves/failures/etc. It is created with the Create
+// method.
+//
+// All functions on the Serf structure are safe to call concurrently.
+type Serf struct {
+	// The clocks for different purposes. These MUST be the first things
+	// in this struct due to Golang issue #599.
+	clock      LamportClock
+	eventClock LamportClock
+	queryClock LamportClock
+
+	broadcasts    *memberlist.TransmitLimitedQueue
+	config        *Config
+	failedMembers []*memberState
+	leftMembers   []*memberState
+	memberlist    *memberlist.Memberlist
+	memberLock    sync.RWMutex
+	members       map[string]*memberState
+
+	// Circular buffers for recent intents, used
+	// in case we get the intent before the relevant event
+	recentLeave      []nodeIntent
+	recentLeaveIndex int
+	recentJoin       []nodeIntent
+	recentJoinIndex  int
+
+	eventBroadcasts *memberlist.TransmitLimitedQueue
+	eventBuffer     []*userEvents
+	eventJoinIgnore bool
+	eventMinTime    LamportTime
+	eventLock       sync.RWMutex
+
+	queryBroadcasts *memberlist.TransmitLimitedQueue
+	queryBuffer     []*queries
+	queryMinTime    LamportTime
+	queryResponse   map[LamportTime]*QueryResponse
+	queryLock       sync.RWMutex
+
+	logger     *log.Logger
+	joinLock   sync.Mutex
+	stateLock  sync.Mutex
+	state      SerfState
+	shutdownCh chan struct{}
+
+	snapshotter *Snapshotter
+	keyManager  *KeyManager
+}
+
+// SerfState is the state of the Serf instance.
+type SerfState int
+
+const (
+	SerfAlive SerfState = iota
+	SerfLeaving
+	SerfLeft
+	SerfShutdown
+)
+
+func (s SerfState) String() string {
+	switch s {
+	case SerfAlive:
+		return "alive"
+	case SerfLeaving:
+		return "leaving"
+	case SerfLeft:
+		return "left"
+	case SerfShutdown:
+		return "shutdown"
+	default:
+		return "unknown"
+	}
+}
+
+// Member is a single member of the Serf cluster.
+type Member struct {
+	Name   string
+	Addr   net.IP
+	Port   uint16
+	Tags   map[string]string
+	Status MemberStatus
+
+	// The minimum, maximum, and current values of the protocol versions
+	// and delegate (Serf) protocol versions that each member can understand
+	// or is speaking.
+	ProtocolMin uint8
+	ProtocolMax uint8
+	ProtocolCur uint8
+	DelegateMin uint8
+	DelegateMax uint8
+	DelegateCur uint8
+}
+
+// MemberStatus is the state that a member is in.
+type MemberStatus int
+
+const (
+	StatusNone MemberStatus = iota
+	StatusAlive
+	StatusLeaving
+	StatusLeft
+	StatusFailed
+)
+
+func (s MemberStatus) String() string {
+	switch s {
+	case StatusNone:
+		return "none"
+	case StatusAlive:
+		return "alive"
+	case StatusLeaving:
+		return "leaving"
+	case StatusLeft:
+		return "left"
+	case StatusFailed:
+		return "failed"
+	default:
+		panic(fmt.Sprintf("unknown MemberStatus: %d", s))
+	}
+}
+
+// memberState is used to track members that are no longer active due to
+// leaving, failing, partitioning, etc. It tracks the member along with
+// when that member was marked as leaving.
+type memberState struct {
+	Member
+	statusLTime LamportTime // lamport clock time of last received message
+	leaveTime   time.Time   // wall clock time of leave
+}
+
+// nodeIntent is used to buffer intents for out-of-order deliveries
+type nodeIntent struct {
+	LTime LamportTime
+	Node  string
+}
+
+// userEvent is used to buffer events to prevent re-delivery
+type userEvent struct {
+	Name    string
+	Payload []byte
+}
+
+func (ue *userEvent) Equals(other *userEvent) bool {
+	if ue.Name != other.Name {
+		return false
+	}
+	if bytes.Compare(ue.Payload, other.Payload) != 0 {
+		return false
+	}
+	return true
+}
+
+// userEvents stores all the user events at a specific time
+type userEvents struct {
+	LTime  LamportTime
+	Events []userEvent
+}
+
+// queries stores all the query ids at a specific time
+type queries struct {
+	LTime    LamportTime
+	QueryIDs []uint32
+}
+
+const (
+	UserEventSizeLimit     = 512        // Maximum byte size for event name and payload
+	QuerySizeLimit         = 1024       // Maximum byte size for query
+	QueryResponseSizeLimit = 1024       // Maximum bytes size for response
+	snapshotSizeLimit      = 128 * 1024 // Maximum 128 KB snapshot
+)
+
+// Create creates a new Serf instance, starting all the background tasks
+// to maintain cluster membership information.
+//
+// After calling this function, the configuration should no longer be used
+// or modified by the caller.
+func Create(conf *Config) (*Serf, error) {
+	conf.Init()
+	if conf.ProtocolVersion < ProtocolVersionMin {
+		return nil, fmt.Errorf("Protocol version '%d' too low. Must be in range: [%d, %d]",
+			conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+	} else if conf.ProtocolVersion > ProtocolVersionMax {
+		return nil, fmt.Errorf("Protocol version '%d' too high. Must be in range: [%d, %d]",
+			conf.ProtocolVersion, ProtocolVersionMin, ProtocolVersionMax)
+	}
+
+	serf := &Serf{
+		config:        conf,
+		logger:        log.New(conf.LogOutput, "", log.LstdFlags),
+		members:       make(map[string]*memberState),
+		queryResponse: make(map[LamportTime]*QueryResponse),
+		shutdownCh:    make(chan struct{}),
+		state:         SerfAlive,
+	}
+
+	// Check that the meta data length is okay
+	if len(serf.encodeTags(conf.Tags)) > memberlist.MetaMaxSize {
+		return nil, fmt.Errorf("Encoded length of tags exceeds limit of %d bytes", memberlist.MetaMaxSize)
+	}
+
+	// Check if serf member event coalescing is enabled
+	if conf.CoalescePeriod > 0 && conf.QuiescentPeriod > 0 && conf.EventCh != nil {
+		c := &memberEventCoalescer{
+			lastEvents:   make(map[string]EventType),
+			latestEvents: make(map[string]coalesceEvent),
+		}
+
+		conf.EventCh = coalescedEventCh(conf.EventCh, serf.shutdownCh,
+			conf.CoalescePeriod, conf.QuiescentPeriod, c)
+	}
+
+	// Check if user event coalescing is enabled
+	if conf.UserCoalescePeriod > 0 && conf.UserQuiescentPeriod > 0 && conf.EventCh != nil {
+		c := &userEventCoalescer{
+			events: make(map[string]*latestUserEvents),
+		}
+
+		conf.EventCh = coalescedEventCh(conf.EventCh, serf.shutdownCh,
+			conf.UserCoalescePeriod, conf.UserQuiescentPeriod, c)
+	}
+
+	// Listen for internal Serf queries. This is setup before the snapshotter, since
+	// we want to capture the query-time, but the internal listener does not passthrough
+	// the queries
+	outCh, err := newSerfQueries(serf, serf.logger, conf.EventCh, serf.shutdownCh)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to setup serf query handler: %v", err)
+	}
+	conf.EventCh = outCh
+
+	// Try access the snapshot
+	var oldClock, oldEventClock, oldQueryClock LamportTime
+	var prev []*PreviousNode
+	if conf.SnapshotPath != "" {
+		eventCh, snap, err := NewSnapshotter(conf.SnapshotPath,
+			snapshotSizeLimit,
+			conf.RejoinAfterLeave,
+			serf.logger,
+			&serf.clock,
+			conf.EventCh,
+			serf.shutdownCh)
+		if err != nil {
+			return nil, fmt.Errorf("Failed to setup snapshot: %v", err)
+		}
+		serf.snapshotter = snap
+		conf.EventCh = eventCh
+		prev = snap.AliveNodes()
+		oldClock = snap.LastClock()
+		oldEventClock = snap.LastEventClock()
+		oldQueryClock = snap.LastQueryClock()
+		serf.eventMinTime = oldEventClock + 1
+		serf.queryMinTime = oldQueryClock + 1
+	}
+
+	// Setup the various broadcast queues, which we use to send our own
+	// custom broadcasts along the gossip channel.
+	serf.broadcasts = &memberlist.TransmitLimitedQueue{
+		NumNodes: func() int {
+			return len(serf.members)
+		},
+		RetransmitMult: conf.MemberlistConfig.RetransmitMult,
+	}
+	serf.eventBroadcasts = &memberlist.TransmitLimitedQueue{
+		NumNodes: func() int {
+			return len(serf.members)
+		},
+		RetransmitMult: conf.MemberlistConfig.RetransmitMult,
+	}
+	serf.queryBroadcasts = &memberlist.TransmitLimitedQueue{
+		NumNodes: func() int {
+			return len(serf.members)
+		},
+		RetransmitMult: conf.MemberlistConfig.RetransmitMult,
+	}
+
+	// Create the buffer for recent intents
+	serf.recentJoin = make([]nodeIntent, conf.RecentIntentBuffer)
+	serf.recentLeave = make([]nodeIntent, conf.RecentIntentBuffer)
+
+	// Create a buffer for events and queries
+	serf.eventBuffer = make([]*userEvents, conf.EventBuffer)
+	serf.queryBuffer = make([]*queries, conf.QueryBuffer)
+
+	// Ensure our lamport clock is at least 1, so that the default
+	// join LTime of 0 does not cause issues
+	serf.clock.Increment()
+	serf.eventClock.Increment()
+	serf.queryClock.Increment()
+
+	// Restore the clock from snap if we have one
+	serf.clock.Witness(oldClock)
+	serf.eventClock.Witness(oldEventClock)
+	serf.queryClock.Witness(oldQueryClock)
+
+	// Modify the memberlist configuration with keys that we set
+	conf.MemberlistConfig.Events = &eventDelegate{serf: serf}
+	conf.MemberlistConfig.Conflict = &conflictDelegate{serf: serf}
+	conf.MemberlistConfig.Delegate = &delegate{serf: serf}
+	conf.MemberlistConfig.DelegateProtocolVersion = conf.ProtocolVersion
+	conf.MemberlistConfig.DelegateProtocolMin = ProtocolVersionMin
+	conf.MemberlistConfig.DelegateProtocolMax = ProtocolVersionMax
+	conf.MemberlistConfig.Name = conf.NodeName
+	conf.MemberlistConfig.ProtocolVersion = ProtocolVersionMap[conf.ProtocolVersion]
+
+	// Setup a merge delegate if necessary
+	if conf.Merge != nil {
+		conf.MemberlistConfig.Merge = &mergeDelegate{serf: serf}
+	}
+
+	// Create the underlying memberlist that will manage membership
+	// and failure detection for the Serf instance.
+	memberlist, err := memberlist.Create(conf.MemberlistConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	serf.memberlist = memberlist
+
+	// Create a key manager for handling all encryption key changes
+	serf.keyManager = &KeyManager{serf: serf}
+
+	// Start the background tasks. See the documentation above each method
+	// for more information on their role.
+	go serf.handleReap()
+	go serf.handleReconnect()
+	go serf.checkQueueDepth("Intent", serf.broadcasts)
+	go serf.checkQueueDepth("Event", serf.eventBroadcasts)
+	go serf.checkQueueDepth("Query", serf.queryBroadcasts)
+
+	// Attempt to re-join the cluster if we have known nodes
+	if len(prev) != 0 {
+		go serf.handleRejoin(prev)
+	}
+
+	return serf, nil
+}
+
+// ProtocolVersion returns the current protocol version in use by Serf.
+// This is the Serf protocol version, not the memberlist protocol version.
+func (s *Serf) ProtocolVersion() uint8 {
+	return s.config.ProtocolVersion
+}
+
+// EncryptionEnabled is a predicate that determines whether or not encryption
+// is enabled, which can be possible in one of 2 cases:
+//   - Single encryption key passed at agent start (no persistence)
+//   - Keyring file provided at agent start
+func (s *Serf) EncryptionEnabled() bool {
+	return s.config.MemberlistConfig.Keyring != nil
+}
+
+// KeyManager returns the key manager for the current Serf instance.
+func (s *Serf) KeyManager() *KeyManager {
+	return s.keyManager
+}
+
+// UserEvent is used to broadcast a custom user event with a given
+// name and payload. The events must be fairly small, and if the
+// size limit is exceeded and error will be returned. If coalesce is enabled,
+// nodes are allowed to coalesce this event. Coalescing is only available
+// starting in v0.2
+func (s *Serf) UserEvent(name string, payload []byte, coalesce bool) error {
+	// Check the size limit
+	if len(name)+len(payload) > UserEventSizeLimit {
+		return fmt.Errorf("user event exceeds limit of %d bytes", UserEventSizeLimit)
+	}
+
+	// Create a message
+	msg := messageUserEvent{
+		LTime:   s.eventClock.Time(),
+		Name:    name,
+		Payload: payload,
+		CC:      coalesce,
+	}
+	s.eventClock.Increment()
+
+	// Process update locally
+	s.handleUserEvent(&msg)
+
+	// Start broadcasting the event
+	raw, err := encodeMessage(messageUserEventType, &msg)
+	if err != nil {
+		return err
+	}
+	s.eventBroadcasts.QueueBroadcast(&broadcast{
+		msg: raw,
+	})
+	return nil
+}
+
+// Query is used to broadcast a new query. The query must be fairly small,
+// and an error will be returned if the size limit is exceeded. This is only
+// available with protocol version 4 and newer. Query parameters are optional,
+// and if not provided, a sane set of defaults will be used.
+func (s *Serf) Query(name string, payload []byte, params *QueryParam) (*QueryResponse, error) {
+	// Check that the latest protocol is in use
+	if s.ProtocolVersion() < 4 {
+		return nil, FeatureNotSupported
+	}
+
+	// Provide default parameters if none given
+	if params == nil {
+		params = s.DefaultQueryParams()
+	} else if params.Timeout == 0 {
+		params.Timeout = s.DefaultQueryTimeout()
+	}
+
+	// Get the local node
+	local := s.memberlist.LocalNode()
+
+	// Encode the filters
+	filters, err := params.encodeFilters()
+	if err != nil {
+		return nil, fmt.Errorf("Failed to format filters: %v", err)
+	}
+
+	// Setup the flags
+	var flags uint32
+	if params.RequestAck {
+		flags |= queryFlagAck
+	}
+
+	// Create a message
+	q := messageQuery{
+		LTime:   s.queryClock.Time(),
+		ID:      uint32(rand.Int31()),
+		Addr:    local.Addr,
+		Port:    local.Port,
+		Filters: filters,
+		Flags:   flags,
+		Timeout: params.Timeout,
+		Name:    name,
+		Payload: payload,
+	}
+
+	// Encode the query
+	raw, err := encodeMessage(messageQueryType, &q)
+	if err != nil {
+		return nil, err
+	}
+
+	// Check the size
+	if len(raw) > QuerySizeLimit {
+		return nil, fmt.Errorf("query exceeds limit of %d bytes", QuerySizeLimit)
+	}
+
+	// Register QueryResponse to track acks and responses
+	resp := newQueryResponse(s.memberlist.NumMembers(), &q)
+	s.registerQueryResponse(params.Timeout, resp)
+
+	// Process query locally
+	s.handleQuery(&q)
+
+	// Start broadcasting the event
+	s.queryBroadcasts.QueueBroadcast(&broadcast{
+		msg: raw,
+	})
+	return resp, nil
+}
+
+// registerQueryResponse is used to setup the listeners for the query,
+// and to schedule closing the query after the timeout.
+func (s *Serf) registerQueryResponse(timeout time.Duration, resp *QueryResponse) {
+	s.queryLock.Lock()
+	defer s.queryLock.Unlock()
+
+	// Map the LTime to the QueryResponse. This is necessarily 1-to-1,
+	// since we increment the time for each new query.
+	s.queryResponse[resp.lTime] = resp
+
+	// Setup a timer to close the response and deregister after the timeout
+	time.AfterFunc(timeout, func() {
+		s.queryLock.Lock()
+		delete(s.queryResponse, resp.lTime)
+		resp.Close()
+		s.queryLock.Unlock()
+	})
+}
+
+// SetTags is used to dynamically update the tags associated with
+// the local node. This will propagate the change to the rest of
+// the cluster. Blocks until a the message is broadcast out.
+func (s *Serf) SetTags(tags map[string]string) error {
+	// Check that the meta data length is okay
+	if len(s.encodeTags(tags)) > memberlist.MetaMaxSize {
+		return fmt.Errorf("Encoded length of tags exceeds limit of %d bytes",
+			memberlist.MetaMaxSize)
+	}
+
+	// Update the config
+	s.config.Tags = tags
+
+	// Trigger a memberlist update
+	return s.memberlist.UpdateNode(s.config.BroadcastTimeout)
+}
+
+// Join joins an existing Serf cluster. Returns the number of nodes
+// successfully contacted. The returned error will be non-nil only in the
+// case that no nodes could be contacted. If ignoreOld is true, then any
+// user messages sent prior to the join will be ignored.
+func (s *Serf) Join(existing []string, ignoreOld bool) (int, error) {
+	// Do a quick state check
+	if s.State() != SerfAlive {
+		return 0, fmt.Errorf("Serf can't Join after Leave or Shutdown")
+	}
+
+	// Hold the joinLock, this is to make eventJoinIgnore safe
+	s.joinLock.Lock()
+	defer s.joinLock.Unlock()
+
+	// Ignore any events from a potential join. This is safe since we hold
+	// the joinLock and nobody else can be doing a Join
+	if ignoreOld {
+		s.eventJoinIgnore = true
+		defer func() {
+			s.eventJoinIgnore = false
+		}()
+	}
+
+	// Have memberlist attempt to join
+	num, err := s.memberlist.Join(existing)
+
+	// If we joined any nodes, broadcast the join message
+	if num > 0 {
+		// Start broadcasting the update
+		if err := s.broadcastJoin(s.clock.Time()); err != nil {
+			return num, err
+		}
+	}
+
+	return num, err
+}
+
+// broadcastJoin broadcasts a new join intent with a
+// given clock value. It is used on either join, or if
+// we need to refute an older leave intent. Cannot be called
+// with the memberLock held.
+func (s *Serf) broadcastJoin(ltime LamportTime) error {
+	// Construct message to update our lamport clock
+	msg := messageJoin{
+		LTime: ltime,
+		Node:  s.config.NodeName,
+	}
+	s.clock.Witness(ltime)
+
+	// Process update locally
+	s.handleNodeJoinIntent(&msg)
+
+	// Start broadcasting the update
+	if err := s.broadcast(messageJoinType, &msg, nil); err != nil {
+		s.logger.Printf("[WARN] serf: Failed to broadcast join intent: %v", err)
+		return err
+	}
+	return nil
+}
+
+// Leave gracefully exits the cluster. It is safe to call this multiple
+// times.
+func (s *Serf) Leave() error {
+	// Check the current state
+	s.stateLock.Lock()
+	if s.state == SerfLeft {
+		s.stateLock.Unlock()
+		return nil
+	} else if s.state == SerfLeaving {
+		s.stateLock.Unlock()
+		return fmt.Errorf("Leave already in progress")
+	} else if s.state == SerfShutdown {
+		s.stateLock.Unlock()
+		return fmt.Errorf("Leave called after Shutdown")
+	}
+	s.state = SerfLeaving
+	s.stateLock.Unlock()
+
+	// If we have a snapshot, mark we are leaving
+	if s.snapshotter != nil {
+		s.snapshotter.Leave()
+	}
+
+	// Construct the message for the graceful leave
+	msg := messageLeave{
+		LTime: s.clock.Time(),
+		Node:  s.config.NodeName,
+	}
+	s.clock.Increment()
+
+	// Process the leave locally
+	s.handleNodeLeaveIntent(&msg)
+
+	// Only broadcast the leave message if there is at least one
+	// other node alive.
+	if s.hasAliveMembers() {
+		notifyCh := make(chan struct{})
+		if err := s.broadcast(messageLeaveType, &msg, notifyCh); err != nil {
+			return err
+		}
+
+		select {
+		case <-notifyCh:
+		case <-time.After(s.config.BroadcastTimeout):
+			return errors.New("timeout while waiting for graceful leave")
+		}
+	}
+
+	// Attempt the memberlist leave
+	err := s.memberlist.Leave(s.config.BroadcastTimeout)
+	if err != nil {
+		return err
+	}
+
+	// Transition to Left only if we not already shutdown
+	s.stateLock.Lock()
+	if s.state != SerfShutdown {
+		s.state = SerfLeft
+	}
+	s.stateLock.Unlock()
+	return nil
+}
+
+// hasAliveMembers is called to check for any alive members other than
+// ourself.
+func (s *Serf) hasAliveMembers() bool {
+	s.memberLock.RLock()
+	defer s.memberLock.RUnlock()
+
+	hasAlive := false
+	for _, m := range s.members {
+		// Skip ourself, we want to know if OTHER members are alive
+		if m.Name == s.config.NodeName {
+			continue
+		}
+
+		if m.Status == StatusAlive {
+			hasAlive = true
+			break
+		}
+	}
+	return hasAlive
+}
+
+// LocalMember returns the Member information for the local node
+func (s *Serf) LocalMember() Member {
+	s.memberLock.RLock()
+	defer s.memberLock.RUnlock()
+	return s.members[s.config.NodeName].Member
+}
+
+// Members returns a point-in-time snapshot of the members of this cluster.
+func (s *Serf) Members() []Member {
+	s.memberLock.RLock()
+	defer s.memberLock.RUnlock()
+
+	members := make([]Member, 0, len(s.members))
+	for _, m := range s.members {
+		members = append(members, m.Member)
+	}
+
+	return members
+}
+
+// RemoveFailedNode forcibly removes a failed node from the cluster
+// immediately, instead of waiting for the reaper to eventually reclaim it.
+// This also has the effect that Serf will no longer attempt to reconnect
+// to this node.
+func (s *Serf) RemoveFailedNode(node string) error {
+	// Construct the message to broadcast
+	msg := messageLeave{
+		LTime: s.clock.Time(),
+		Node:  node,
+	}
+	s.clock.Increment()
+
+	// Process our own event
+	s.handleNodeLeaveIntent(&msg)
+
+	// If we have no members, then we don't need to broadcast
+	if !s.hasAliveMembers() {
+		return nil
+	}
+
+	// Broadcast the remove
+	notifyCh := make(chan struct{})
+	if err := s.broadcast(messageLeaveType, &msg, notifyCh); err != nil {
+		return err
+	}
+
+	// Wait for the broadcast
+	select {
+	case <-notifyCh:
+	case <-time.After(s.config.BroadcastTimeout):
+		return fmt.Errorf("timed out broadcasting node removal")
+	}
+
+	return nil
+}
+
+// Shutdown forcefully shuts down the Serf instance, stopping all network
+// activity and background maintenance associated with the instance.
+//
+// This is not a graceful shutdown, and should be preceded by a call
+// to Leave. Otherwise, other nodes in the cluster will detect this node's
+// exit as a node failure.
+//
+// It is safe to call this method multiple times.
+func (s *Serf) Shutdown() error {
+	s.stateLock.Lock()
+	defer s.stateLock.Unlock()
+
+	if s.state == SerfShutdown {
+		return nil
+	}
+
+	if s.state != SerfLeft {
+		s.logger.Printf("[WARN] serf: Shutdown without a Leave")
+	}
+
+	s.state = SerfShutdown
+	close(s.shutdownCh)
+
+	err := s.memberlist.Shutdown()
+	if err != nil {
+		return err
+	}
+
+	// Wait for the snapshoter to finish if we have one
+	if s.snapshotter != nil {
+		s.snapshotter.Wait()
+	}
+
+	return nil
+}
+
+// ShutdownCh returns a channel that can be used to wait for
+// Serf to shutdown.
+func (s *Serf) ShutdownCh() <-chan struct{} {
+	return s.shutdownCh
+}
+
+// Memberlist is used to get access to the underlying Memberlist instance
+func (s *Serf) Memberlist() *memberlist.Memberlist {
+	return s.memberlist
+}
+
+// State is the current state of this Serf instance.
+func (s *Serf) State() SerfState {
+	s.stateLock.Lock()
+	defer s.stateLock.Unlock()
+	return s.state
+}
+
+// broadcast takes a Serf message type, encodes it for the wire, and queues
+// the broadcast. If a notify channel is given, this channel will be closed
+// when the broadcast is sent.
+func (s *Serf) broadcast(t messageType, msg interface{}, notify chan<- struct{}) error {
+	raw, err := encodeMessage(t, msg)
+	if err != nil {
+		return err
+	}
+
+	s.broadcasts.QueueBroadcast(&broadcast{
+		msg:    raw,
+		notify: notify,
+	})
+	return nil
+}
+
+// handleNodeJoin is called when a node join event is received
+// from memberlist.
+func (s *Serf) handleNodeJoin(n *memberlist.Node) {
+	s.memberLock.Lock()
+	defer s.memberLock.Unlock()
+
+	var oldStatus MemberStatus
+	member, ok := s.members[n.Name]
+	if !ok {
+		oldStatus = StatusNone
+		member = &memberState{
+			Member: Member{
+				Name:   n.Name,
+				Addr:   net.IP(n.Addr),
+				Port:   n.Port,
+				Tags:   s.decodeTags(n.Meta),
+				Status: StatusAlive,
+			},
+		}
+
+		// Check if we have a join intent and use the LTime
+		if join := recentIntent(s.recentJoin, n.Name); join != nil {
+			member.statusLTime = join.LTime
+		}
+
+		// Check if we have a leave intent
+		if leave := recentIntent(s.recentLeave, n.Name); leave != nil {
+			if leave.LTime > member.statusLTime {
+				member.Status = StatusLeaving
+				member.statusLTime = leave.LTime
+			}
+		}
+
+		s.members[n.Name] = member
+	} else {
+		oldStatus = member.Status
+		member.Status = StatusAlive
+		member.leaveTime = time.Time{}
+		member.Addr = net.IP(n.Addr)
+		member.Port = n.Port
+		member.Tags = s.decodeTags(n.Meta)
+	}
+
+	// Update the protocol versions every time we get an event
+	member.ProtocolMin = n.PMin
+	member.ProtocolMax = n.PMax
+	member.ProtocolCur = n.PCur
+	member.DelegateMin = n.DMin
+	member.DelegateMax = n.DMax
+	member.DelegateCur = n.DCur
+
+	// If node was previously in a failed state, then clean up some
+	// internal accounting.
+	// TODO(mitchellh): needs tests to verify not reaped
+	if oldStatus == StatusFailed || oldStatus == StatusLeft {
+		s.failedMembers = removeOldMember(s.failedMembers, member.Name)
+		s.leftMembers = removeOldMember(s.leftMembers, member.Name)
+	}
+
+	// Update some metrics
+	metrics.IncrCounter([]string{"serf", "member", "join"}, 1)
+
+	// Send an event along
+	s.logger.Printf("[INFO] serf: EventMemberJoin: %s %s",
+		member.Member.Name, member.Member.Addr)
+	if s.config.EventCh != nil {
+		s.config.EventCh <- MemberEvent{
+			Type:    EventMemberJoin,
+			Members: []Member{member.Member},
+		}
+	}
+}
+
+// handleNodeLeave is called when a node leave event is received
+// from memberlist.
+func (s *Serf) handleNodeLeave(n *memberlist.Node) {
+	s.memberLock.Lock()
+	defer s.memberLock.Unlock()
+
+	member, ok := s.members[n.Name]
+	if !ok {
+		// We've never even heard of this node that is supposedly
+		// leaving. Just ignore it completely.
+		return
+	}
+
+	switch member.Status {
+	case StatusLeaving:
+		member.Status = StatusLeft
+		member.leaveTime = time.Now()
+		s.leftMembers = append(s.leftMembers, member)
+	case StatusAlive:
+		member.Status = StatusFailed
+		member.leaveTime = time.Now()
+		s.failedMembers = append(s.failedMembers, member)
+	default:
+		// Unknown state that it was in? Just don't do anything
+		s.logger.Printf("[WARN] serf: Bad state when leave: %d", member.Status)
+		return
+	}
+
+	// Send an event along
+	event := EventMemberLeave
+	eventStr := "EventMemberLeave"
+	if member.Status != StatusLeft {
+		event = EventMemberFailed
+		eventStr = "EventMemberFailed"
+	}
+
+	// Update some metrics
+	metrics.IncrCounter([]string{"serf", "member", member.Status.String()}, 1)
+
+	s.logger.Printf("[INFO] serf: %s: %s %s",
+		eventStr, member.Member.Name, member.Member.Addr)
+	if s.config.EventCh != nil {
+		s.config.EventCh <- MemberEvent{
+			Type:    event,
+			Members: []Member{member.Member},
+		}
+	}
+}
+
+// handleNodeUpdate is called when a node meta data update
+// has taken place
+func (s *Serf) handleNodeUpdate(n *memberlist.Node) {
+	s.memberLock.Lock()
+	defer s.memberLock.Unlock()
+
+	member, ok := s.members[n.Name]
+	if !ok {
+		// We've never even heard of this node that is updating.
+		// Just ignore it completely.
+		return
+	}
+
+	// Update the member attributes
+	member.Addr = net.IP(n.Addr)
+	member.Port = n.Port
+	member.Tags = s.decodeTags(n.Meta)
+
+	// Update some metrics
+	metrics.IncrCounter([]string{"serf", "member", "update"}, 1)
+
+	// Send an event along
+	s.logger.Printf("[INFO] serf: EventMemberUpdate: %s", member.Member.Name)
+	if s.config.EventCh != nil {
+		s.config.EventCh <- MemberEvent{
+			Type:    EventMemberUpdate,
+			Members: []Member{member.Member},
+		}
+	}
+}
+
+// handleNodeLeaveIntent is called when an intent to leave is received.
+func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool {
+	// Witness a potentially newer time
+	s.clock.Witness(leaveMsg.LTime)
+
+	s.memberLock.Lock()
+	defer s.memberLock.Unlock()
+
+	member, ok := s.members[leaveMsg.Node]
+	if !ok {
+		// If we've already seen this message don't rebroadcast
+		if recentIntent(s.recentLeave, leaveMsg.Node) != nil {
+			return false
+		}
+
+		// We don't know this member so store it in a buffer for now
+		s.recentLeave[s.recentLeaveIndex] = nodeIntent{
+			LTime: leaveMsg.LTime,
+			Node:  leaveMsg.Node,
+		}
+		s.recentLeaveIndex = (s.recentLeaveIndex + 1) % len(s.recentLeave)
+		return true
+	}
+
+	// If the message is old, then it is irrelevant and we can skip it
+	if leaveMsg.LTime <= member.statusLTime {
+		return false
+	}
+
+	// Refute us leaving if we are in the alive state
+	// Must be done in another goroutine since we have the memberLock
+	if leaveMsg.Node == s.config.NodeName && s.state == SerfAlive {
+		s.logger.Printf("[DEBUG] serf: Refuting an older leave intent")
+		go s.broadcastJoin(s.clock.Time())
+		return false
+	}
+
+	// State transition depends on current state
+	switch member.Status {
+	case StatusAlive:
+		member.Status = StatusLeaving
+		member.statusLTime = leaveMsg.LTime
+		return true
+	case StatusFailed:
+		member.Status = StatusLeft
+		member.statusLTime = leaveMsg.LTime
+
+		// Remove from the failed list and add to the left list. We add
+		// to the left list so that when we do a sync, other nodes will
+		// remove it from their failed list.
+		s.failedMembers = removeOldMember(s.failedMembers, member.Name)
+		s.leftMembers = append(s.leftMembers, member)
+
+		return true
+	default:
+		return false
+	}
+}
+
+// handleNodeJoinIntent is called when a node broadcasts a
+// join message to set the lamport time of its join
+func (s *Serf) handleNodeJoinIntent(joinMsg *messageJoin) bool {
+	// Witness a potentially newer time
+	s.clock.Witness(joinMsg.LTime)
+
+	s.memberLock.Lock()
+	defer s.memberLock.Unlock()
+
+	member, ok := s.members[joinMsg.Node]
+	if !ok {
+		// If we've already seen this message don't rebroadcast
+		if recentIntent(s.recentJoin, joinMsg.Node) != nil {
+			return false
+		}
+
+		// We don't know this member so store it in a buffer for now
+		s.recentJoin[s.recentJoinIndex] = nodeIntent{LTime: joinMsg.LTime, Node: joinMsg.Node}
+		s.recentJoinIndex = (s.recentJoinIndex + 1) % len(s.recentJoin)
+		return true
+	}
+
+	// Check if this time is newer than what we have
+	if joinMsg.LTime <= member.statusLTime {
+		return false
+	}
+
+	// Update the LTime
+	member.statusLTime = joinMsg.LTime
+
+	// If we are in the leaving state, we should go back to alive,
+	// since the leaving message must have been for an older time
+	if member.Status == StatusLeaving {
+		member.Status = StatusAlive
+	}
+	return true
+}
+
+// handleUserEvent is called when a user event broadcast is
+// received. Returns if the message should be rebroadcast.
+func (s *Serf) handleUserEvent(eventMsg *messageUserEvent) bool {
+	// Witness a potentially newer time
+	s.eventClock.Witness(eventMsg.LTime)
+
+	s.eventLock.Lock()
+	defer s.eventLock.Unlock()
+
+	// Ignore if it is before our minimum event time
+	if eventMsg.LTime < s.eventMinTime {
+		return false
+	}
+
+	// Check if this message is too old
+	curTime := s.eventClock.Time()
+	if curTime > LamportTime(len(s.eventBuffer)) &&
+		eventMsg.LTime < curTime-LamportTime(len(s.eventBuffer)) {
+		s.logger.Printf(
+			"[WARN] serf: received old event %s from time %d (current: %d)",
+			eventMsg.Name,
+			eventMsg.LTime,
+			s.eventClock.Time())
+		return false
+	}
+
+	// Check if we've already seen this
+	idx := eventMsg.LTime % LamportTime(len(s.eventBuffer))
+	seen := s.eventBuffer[idx]
+	userEvent := userEvent{Name: eventMsg.Name, Payload: eventMsg.Payload}
+	if seen != nil && seen.LTime == eventMsg.LTime {
+		for _, previous := range seen.Events {
+			if previous.Equals(&userEvent) {
+				return false
+			}
+		}
+	} else {
+		seen = &userEvents{LTime: eventMsg.LTime}
+		s.eventBuffer[idx] = seen
+	}
+
+	// Add to recent events
+	seen.Events = append(seen.Events, userEvent)
+
+	// Update some metrics
+	metrics.IncrCounter([]string{"serf", "events"}, 1)
+	metrics.IncrCounter([]string{"serf", "events", eventMsg.Name}, 1)
+
+	if s.config.EventCh != nil {
+		s.config.EventCh <- UserEvent{
+			LTime:    eventMsg.LTime,
+			Name:     eventMsg.Name,
+			Payload:  eventMsg.Payload,
+			Coalesce: eventMsg.CC,
+		}
+	}
+	return true
+}
+
+// handleQuery is called when a query broadcast is
+// received. Returns if the message should be rebroadcast.
+func (s *Serf) handleQuery(query *messageQuery) bool {
+	// Witness a potentially newer time
+	s.queryClock.Witness(query.LTime)
+
+	s.queryLock.Lock()
+	defer s.queryLock.Unlock()
+
+	// Ignore if it is before our minimum query time
+	if query.LTime < s.queryMinTime {
+		return false
+	}
+
+	// Check if this message is too old
+	curTime := s.queryClock.Time()
+	if curTime > LamportTime(len(s.queryBuffer)) &&
+		query.LTime < curTime-LamportTime(len(s.queryBuffer)) {
+		s.logger.Printf(
+			"[WARN] serf: received old query %s from time %d (current: %d)",
+			query.Name,
+			query.LTime,
+			s.queryClock.Time())
+		return false
+	}
+
+	// Check if we've already seen this
+	idx := query.LTime % LamportTime(len(s.queryBuffer))
+	seen := s.queryBuffer[idx]
+	if seen != nil && seen.LTime == query.LTime {
+		for _, previous := range seen.QueryIDs {
+			if previous == query.ID {
+				// Seen this ID already
+				return false
+			}
+		}
+	} else {
+		seen = &queries{LTime: query.LTime}
+		s.queryBuffer[idx] = seen
+	}
+
+	// Add to recent queries
+	seen.QueryIDs = append(seen.QueryIDs, query.ID)
+
+	// Update some metrics
+	metrics.IncrCounter([]string{"serf", "queries"}, 1)
+	metrics.IncrCounter([]string{"serf", "queries", query.Name}, 1)
+
+	// Check if we should rebroadcast, this may be disabled by a flag
+	rebroadcast := true
+	if query.NoBroadcast() {
+		rebroadcast = false
+	}
+
+	// Filter the query
+	if !s.shouldProcessQuery(query.Filters) {
+		// Even if we don't process it further, we should rebroadcast,
+		// since it is the first time we've seen this.
+		return rebroadcast
+	}
+
+	// Send ack if requested, without waiting for client to Respond()
+	if query.Ack() {
+		ack := messageQueryResponse{
+			LTime: query.LTime,
+			ID:    query.ID,
+			From:  s.config.NodeName,
+			Flags: queryFlagAck,
+		}
+		raw, err := encodeMessage(messageQueryResponseType, &ack)
+		if err != nil {
+			s.logger.Printf("[ERR] serf: failed to format ack: %v", err)
+		} else {
+			addr := net.UDPAddr{IP: query.Addr, Port: int(query.Port)}
+			if err := s.memberlist.SendTo(&addr, raw); err != nil {
+				s.logger.Printf("[ERR] serf: failed to send ack: %v", err)
+			}
+		}
+	}
+
+	if s.config.EventCh != nil {
+		s.config.EventCh <- &Query{
+			LTime:    query.LTime,
+			Name:     query.Name,
+			Payload:  query.Payload,
+			serf:     s,
+			id:       query.ID,
+			addr:     query.Addr,
+			port:     query.Port,
+			deadline: time.Now().Add(query.Timeout),
+		}
+	}
+	return rebroadcast
+}
+
+// handleResponse is called when a query response is
+// received.
+func (s *Serf) handleQueryResponse(resp *messageQueryResponse) {
+	// Look for a corresponding QueryResponse
+	s.queryLock.RLock()
+	query, ok := s.queryResponse[resp.LTime]
+	s.queryLock.RUnlock()
+	if !ok {
+		s.logger.Printf("[WARN] serf: reply for non-running query (LTime: %d, ID: %d) From: %s",
+			resp.LTime, resp.ID, resp.From)
+		return
+	}
+
+	// Verify the ID matches
+	if query.id != resp.ID {
+		s.logger.Printf("[WARN] serf: query reply ID mismatch (Local: %d, Response: %d)",
+			query.id, resp.ID)
+		return
+	}
+
+	// Check if the query is closed
+	if query.Finished() {
+		return
+	}
+
+	// Process each type of response
+	if resp.Ack() {
+		metrics.IncrCounter([]string{"serf", "query_acks"}, 1)
+		select {
+		case query.ackCh <- resp.From:
+		default:
+			s.logger.Printf("[WARN] serf: Failed to delivery query ack, dropping")
+		}
+	} else {
+		metrics.IncrCounter([]string{"serf", "query_responses"}, 1)
+		select {
+		case query.respCh <- NodeResponse{From: resp.From, Payload: resp.Payload}:
+		default:
+			s.logger.Printf("[WARN] serf: Failed to delivery query response, dropping")
+		}
+	}
+}
+
+// handleNodeConflict is invoked when a join detects a conflict over a name.
+// This means two different nodes (IP/Port) are claiming the same name. Memberlist
+// will reject the "new" node mapping, but we can still be notified
+func (s *Serf) handleNodeConflict(existing, other *memberlist.Node) {
+	// Log a basic warning if the node is not us...
+	if existing.Name != s.config.NodeName {
+		s.logger.Printf("[WARN] serf: Name conflict for '%s' both %s:%d and %s:%d are claiming",
+			existing.Name, existing.Addr, existing.Port, other.Addr, other.Port)
+		return
+	}
+
+	// The current node is conflicting! This is an error
+	s.logger.Printf("[ERR] serf: Node name conflicts with another node at %s:%d. Names must be unique! (Resolution enabled: %v)",
+		other.Addr, other.Port, s.config.EnableNameConflictResolution)
+
+	// If automatic resolution is enabled, kick off the resolution
+	if s.config.EnableNameConflictResolution {
+		go s.resolveNodeConflict()
+	}
+}
+
+// resolveNodeConflict is used to determine which node should remain during
+// a name conflict. This is done by running an internal query.
+func (s *Serf) resolveNodeConflict() {
+	// Get the local node
+	local := s.memberlist.LocalNode()
+
+	// Start a name resolution query
+	qName := internalQueryName(conflictQuery)
+	payload := []byte(s.config.NodeName)
+	resp, err := s.Query(qName, payload, nil)
+	if err != nil {
+		s.logger.Printf("[ERR] serf: Failed to start name resolution query: %v", err)
+		return
+	}
+
+	// Counter to determine winner
+	var responses, matching int
+
+	// Gather responses
+	respCh := resp.ResponseCh()
+	for r := range respCh {
+		// Decode the response
+		if len(r.Payload) < 1 || messageType(r.Payload[0]) != messageConflictResponseType {
+			s.logger.Printf("[ERR] serf: Invalid conflict query response type: %v", r.Payload)
+			continue
+		}
+		var member Member
+		if err := decodeMessage(r.Payload[1:], &member); err != nil {
+			s.logger.Printf("[ERR] serf: Failed to decode conflict query response: %v", err)
+			continue
+		}
+
+		// Update the counters
+		responses++
+		if bytes.Equal(member.Addr, local.Addr) && member.Port == local.Port {
+			matching++
+		}
+	}
+
+	// Query over, determine if we should live
+	majority := (responses / 2) + 1
+	if matching >= majority {
+		s.logger.Printf("[INFO] serf: majority in name conflict resolution [%d / %d]",
+			matching, responses)
+		return
+	}
+
+	// Since we lost the vote, we need to exit
+	s.logger.Printf("[WARN] serf: minority in name conflict resolution, quiting [%d / %d]",
+		matching, responses)
+	if err := s.Shutdown(); err != nil {
+		s.logger.Printf("[ERR] serf: Failed to shutdown: %v", err)
+	}
+}
+
+// handleReap periodically reaps the list of failed and left members.
+func (s *Serf) handleReap() {
+	for {
+		select {
+		case <-time.After(s.config.ReapInterval):
+			s.memberLock.Lock()
+			s.failedMembers = s.reap(s.failedMembers, s.config.ReconnectTimeout)
+			s.leftMembers = s.reap(s.leftMembers, s.config.TombstoneTimeout)
+			s.memberLock.Unlock()
+		case <-s.shutdownCh:
+			return
+		}
+	}
+}
+
+// handleReconnect attempts to reconnect to recently failed nodes
+// on configured intervals.
+func (s *Serf) handleReconnect() {
+	for {
+		select {
+		case <-time.After(s.config.ReconnectInterval):
+			s.reconnect()
+		case <-s.shutdownCh:
+			return
+		}
+	}
+}
+
+// reap is called with a list of old members and a timeout, and removes
+// members that have exceeded the timeout. The members are removed from
+// both the old list and the members itself. Locking is left to the caller.
+func (s *Serf) reap(old []*memberState, timeout time.Duration) []*memberState {
+	now := time.Now()
+	n := len(old)
+	for i := 0; i < n; i++ {
+		m := old[i]
+
+		// Skip if the timeout is not yet reached
+		if now.Sub(m.leaveTime) <= timeout {
+			continue
+		}
+
+		// Delete from the list
+		old[i], old[n-1] = old[n-1], nil
+		old = old[:n-1]
+		n--
+		i--
+
+		// Delete from members
+		delete(s.members, m.Name)
+
+		// Send an event along
+		s.logger.Printf("[INFO] serf: EventMemberReap: %s", m.Name)
+		if s.config.EventCh != nil {
+			s.config.EventCh <- MemberEvent{
+				Type:    EventMemberReap,
+				Members: []Member{m.Member},
+			}
+		}
+	}
+
+	return old
+}
+
+// reconnect attempts to reconnect to recently fail nodes.
+func (s *Serf) reconnect() {
+	s.memberLock.RLock()
+
+	// Nothing to do if there are no failed members
+	n := len(s.failedMembers)
+	if n == 0 {
+		s.memberLock.RUnlock()
+		return
+	}
+
+	// Probability we should attempt to reconect is given
+	// by num failed / (num members - num failed - num left)
+	// This means that we probabilistically expect the cluster
+	// to attempt to connect to each failed member once per
+	// reconnect interval
+	numFailed := float32(len(s.failedMembers))
+	numAlive := float32(len(s.members) - len(s.failedMembers) - len(s.leftMembers))
+	if numAlive == 0 {
+		numAlive = 1 // guard against zero divide
+	}
+	prob := numFailed / numAlive
+	if rand.Float32() > prob {
+		s.memberLock.RUnlock()
+		s.logger.Printf("[DEBUG] serf: forgoing reconnect for random throttling")
+		return
+	}
+
+	// Select a random member to try and join
+	idx := int(rand.Uint32() % uint32(n))
+	mem := s.failedMembers[idx]
+	s.memberLock.RUnlock()
+
+	// Format the addr
+	addr := net.UDPAddr{IP: mem.Addr, Port: int(mem.Port)}
+	s.logger.Printf("[INFO] serf: attempting reconnect to %v %s", mem.Name, addr.String())
+
+	// Attempt to join at the memberlist level
+	s.memberlist.Join([]string{addr.String()})
+}
+
+// checkQueueDepth periodically checks the size of a queue to see if
+// it is too large
+func (s *Serf) checkQueueDepth(name string, queue *memberlist.TransmitLimitedQueue) {
+	for {
+		select {
+		case <-time.After(time.Second):
+			numq := queue.NumQueued()
+			metrics.AddSample([]string{"serf", "queue", name}, float32(numq))
+			if numq >= s.config.QueueDepthWarning {
+				s.logger.Printf("[WARN] serf: %s queue depth: %d", name, numq)
+			}
+			if numq > s.config.MaxQueueDepth {
+				s.logger.Printf("[WARN] serf: %s queue depth (%d) exceeds limit (%d), dropping messages!",
+					name, numq, s.config.MaxQueueDepth)
+				queue.Prune(s.config.MaxQueueDepth)
+			}
+		case <-s.shutdownCh:
+			return
+		}
+	}
+}
+
+// removeOldMember is used to remove an old member from a list of old
+// members.
+func removeOldMember(old []*memberState, name string) []*memberState {
+	for i, m := range old {
+		if m.Name == name {
+			n := len(old)
+			old[i], old[n-1] = old[n-1], nil
+			return old[:n-1]
+		}
+	}
+
+	return old
+}
+
+// recentIntent checks the recent intent buffer for a matching
+// entry for a given node, and either returns the message or nil
+func recentIntent(recent []nodeIntent, node string) (intent *nodeIntent) {
+	for i := 0; i < len(recent); i++ {
+		// Break fast if we hit a zero entry
+		if recent[i].LTime == 0 {
+			break
+		}
+
+		// Check for a node match
+		if recent[i].Node == node {
+			// Take the most recent entry
+			if intent == nil || recent[i].LTime > intent.LTime {
+				intent = &recent[i]
+			}
+		}
+	}
+	return
+}
+
+// handleRejoin attempts to reconnect to previously known alive nodes
+func (s *Serf) handleRejoin(previous []*PreviousNode) {
+	for _, prev := range previous {
+		// Do not attempt to join ourself
+		if prev.Name == s.config.NodeName {
+			continue
+		}
+
+		s.logger.Printf("[INFO] serf: Attempting re-join to previously known node: %s", prev)
+		_, err := s.memberlist.Join([]string{prev.Addr})
+		if err == nil {
+			s.logger.Printf("[INFO] serf: Re-joined to previously known node: %s", prev)
+			return
+		}
+	}
+	s.logger.Printf("[WARN] serf: Failed to re-join any previously known node")
+}
+
+// encodeTags is used to encode a tag map
+func (s *Serf) encodeTags(tags map[string]string) []byte {
+	// Support role-only backwards compatibility
+	if s.ProtocolVersion() < 3 {
+		role := tags["role"]
+		return []byte(role)
+	}
+
+	// Use a magic byte prefix and msgpack encode the tags
+	var buf bytes.Buffer
+	buf.WriteByte(tagMagicByte)
+	enc := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
+	if err := enc.Encode(tags); err != nil {
+		panic(fmt.Sprintf("Failed to encode tags: %v", err))
+	}
+	return buf.Bytes()
+}
+
+// decodeTags is used to decode a tag map
+func (s *Serf) decodeTags(buf []byte) map[string]string {
+	tags := make(map[string]string)
+
+	// Backwards compatibility mode
+	if len(buf) == 0 || buf[0] != tagMagicByte {
+		tags["role"] = string(buf)
+		return tags
+	}
+
+	// Decode the tags
+	r := bytes.NewReader(buf[1:])
+	dec := codec.NewDecoder(r, &codec.MsgpackHandle{})
+	if err := dec.Decode(&tags); err != nil {
+		s.logger.Printf("[ERR] serf: Failed to decode tags: %v", err)
+	}
+	return tags
+}
+
+// Stats is used to provide operator debugging information
+func (s *Serf) Stats() map[string]string {
+	toString := func(v uint64) string {
+		return strconv.FormatUint(v, 10)
+	}
+	stats := map[string]string{
+		"members":      toString(uint64(len(s.members))),
+		"failed":       toString(uint64(len(s.failedMembers))),
+		"left":         toString(uint64(len(s.leftMembers))),
+		"member_time":  toString(uint64(s.clock.Time())),
+		"event_time":   toString(uint64(s.eventClock.Time())),
+		"query_time":   toString(uint64(s.queryClock.Time())),
+		"intent_queue": toString(uint64(s.broadcasts.NumQueued())),
+		"event_queue":  toString(uint64(s.eventBroadcasts.NumQueued())),
+		"query_queue":  toString(uint64(s.queryBroadcasts.NumQueued())),
+		"encrypted":    fmt.Sprintf("%v", s.EncryptionEnabled()),
+	}
+	return stats
+}
+
+// WriteKeyringFile will serialize the current keyring and save it to a file.
+func (s *Serf) writeKeyringFile() error {
+	if len(s.config.KeyringFile) == 0 {
+		return nil
+	}
+
+	keyring := s.config.MemberlistConfig.Keyring
+	keysRaw := keyring.GetKeys()
+	keysEncoded := make([]string, len(keysRaw))
+
+	for i, key := range keysRaw {
+		keysEncoded[i] = base64.StdEncoding.EncodeToString(key)
+	}
+
+	encodedKeys, err := json.MarshalIndent(keysEncoded, "", "  ")
+	if err != nil {
+		return fmt.Errorf("Failed to encode keys: %s", err)
+	}
+
+	// Use 0600 for permissions because key data is sensitive
+	if err = ioutil.WriteFile(s.config.KeyringFile, encodedKeys, 0600); err != nil {
+		return fmt.Errorf("Failed to write keyring file: %s", err)
+	}
+
+	// Success!
+	return nil
+}

+ 442 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf_internals_test.go

@@ -0,0 +1,442 @@
+package serf
+
+import (
+	"github.com/hashicorp/memberlist"
+	"github.com/hashicorp/serf/testutil"
+	"testing"
+)
+
+func TestSerf_joinLeave_ltime(t *testing.T) {
+	s1Config := testConfig()
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if s2.members[s1.config.NodeName].statusLTime != 1 {
+		t.Fatalf("join time is not valid %d",
+			s2.members[s1.config.NodeName].statusLTime)
+	}
+
+	if s2.clock.Time() <= s2.members[s1.config.NodeName].statusLTime {
+		t.Fatalf("join should increment")
+	}
+	oldClock := s2.clock.Time()
+
+	err = s1.Leave()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// s1 clock should exceed s2 due to leave
+	if s2.clock.Time() <= oldClock {
+		t.Fatalf("leave should increment (%d / %d)",
+			s2.clock.Time(), oldClock)
+	}
+}
+
+func TestSerf_join_pendingIntent(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.recentJoin[0] = nodeIntent{5, "test"}
+
+	n := memberlist.Node{Name: "test",
+		Addr: nil,
+		Meta: []byte("test"),
+	}
+
+	s.handleNodeJoin(&n)
+
+	mem := s.members["test"]
+	if mem.statusLTime != 5 {
+		t.Fatalf("bad join time")
+	}
+	if mem.Status != StatusAlive {
+		t.Fatalf("bad status")
+	}
+}
+
+func TestSerf_join_pendingIntents(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.recentJoin[0] = nodeIntent{5, "test"}
+	s.recentLeave[0] = nodeIntent{6, "test"}
+
+	n := memberlist.Node{Name: "test",
+		Addr: nil,
+		Meta: []byte("test"),
+	}
+
+	s.handleNodeJoin(&n)
+
+	mem := s.members["test"]
+	if mem.statusLTime != 6 {
+		t.Fatalf("bad join time")
+	}
+	if mem.Status != StatusLeaving {
+		t.Fatalf("bad status")
+	}
+}
+
+func TestSerf_leaveIntent_bufferEarly(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	// Deliver a leave intent message early
+	j := messageLeave{LTime: 10, Node: "test"}
+	if !s.handleNodeLeaveIntent(&j) {
+		t.Fatalf("should rebroadcast")
+	}
+	if s.handleNodeLeaveIntent(&j) {
+		t.Fatalf("should not rebroadcast")
+	}
+
+	// Check that we buffered
+	if s.recentLeaveIndex != 1 {
+		t.Fatalf("bad index")
+	}
+	if s.recentLeave[0].Node != "test" || s.recentLeave[0].LTime != 10 {
+		t.Fatalf("bad buffer")
+	}
+}
+
+func TestSerf_leaveIntent_oldMessage(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.members["test"] = &memberState{
+		Member: Member{
+			Status: StatusAlive,
+		},
+		statusLTime: 12,
+	}
+
+	j := messageLeave{LTime: 10, Node: "test"}
+	if s.handleNodeLeaveIntent(&j) {
+		t.Fatalf("should not rebroadcast")
+	}
+
+	if s.recentLeaveIndex != 0 {
+		t.Fatalf("bad index")
+	}
+}
+
+func TestSerf_leaveIntent_newer(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.members["test"] = &memberState{
+		Member: Member{
+			Status: StatusAlive,
+		},
+		statusLTime: 12,
+	}
+
+	j := messageLeave{LTime: 14, Node: "test"}
+	if !s.handleNodeLeaveIntent(&j) {
+		t.Fatalf("should rebroadcast")
+	}
+
+	if s.recentLeaveIndex != 0 {
+		t.Fatalf("bad index")
+	}
+
+	if s.members["test"].Status != StatusLeaving {
+		t.Fatalf("should update status")
+	}
+
+	if s.clock.Time() != 15 {
+		t.Fatalf("should update clock")
+	}
+}
+
+func TestSerf_joinIntent_bufferEarly(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	// Deliver a join intent message early
+	j := messageJoin{LTime: 10, Node: "test"}
+	if !s.handleNodeJoinIntent(&j) {
+		t.Fatalf("should rebroadcast")
+	}
+	if s.handleNodeJoinIntent(&j) {
+		t.Fatalf("should not rebroadcast")
+	}
+
+	// Check that we buffered
+	if s.recentJoinIndex != 1 {
+		t.Fatalf("bad index")
+	}
+	if s.recentJoin[0].Node != "test" || s.recentJoin[0].LTime != 10 {
+		t.Fatalf("bad buffer")
+	}
+}
+
+func TestSerf_joinIntent_oldMessage(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.members["test"] = &memberState{
+		statusLTime: 12,
+	}
+
+	j := messageJoin{LTime: 10, Node: "test"}
+	if s.handleNodeJoinIntent(&j) {
+		t.Fatalf("should not rebroadcast")
+	}
+
+	if s.recentJoinIndex != 0 {
+		t.Fatalf("bad index")
+	}
+}
+
+func TestSerf_joinIntent_newer(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.members["test"] = &memberState{
+		statusLTime: 12,
+	}
+
+	// Deliver a join intent message early
+	j := messageJoin{LTime: 14, Node: "test"}
+	if !s.handleNodeJoinIntent(&j) {
+		t.Fatalf("should rebroadcast")
+	}
+
+	if s.recentJoinIndex != 0 {
+		t.Fatalf("bad index")
+	}
+
+	if s.members["test"].statusLTime != 14 {
+		t.Fatalf("should update join time")
+	}
+
+	if s.clock.Time() != 15 {
+		t.Fatalf("should update clock")
+	}
+}
+
+func TestSerf_joinIntent_resetLeaving(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	s.members["test"] = &memberState{
+		Member: Member{
+			Status: StatusLeaving,
+		},
+		statusLTime: 12,
+	}
+
+	j := messageJoin{LTime: 14, Node: "test"}
+	if !s.handleNodeJoinIntent(&j) {
+		t.Fatalf("should rebroadcast")
+	}
+
+	if s.recentJoinIndex != 0 {
+		t.Fatalf("bad index")
+	}
+
+	if s.members["test"].statusLTime != 14 {
+		t.Fatalf("should update join time")
+	}
+	if s.members["test"].Status != StatusAlive {
+		t.Fatalf("should update status")
+	}
+
+	if s.clock.Time() != 15 {
+		t.Fatalf("should update clock")
+	}
+}
+
+func TestSerf_userEvent_oldMessage(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	// increase the ltime artificially
+	s.eventClock.Witness(LamportTime(c.EventBuffer + 1000))
+
+	msg := messageUserEvent{
+		LTime:   1,
+		Name:    "old",
+		Payload: nil,
+	}
+	if s.handleUserEvent(&msg) {
+		t.Fatalf("should not rebroadcast")
+	}
+}
+
+func TestSerf_userEvent_sameClock(t *testing.T) {
+	eventCh := make(chan Event, 4)
+	c := testConfig()
+	c.EventCh = eventCh
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	msg := messageUserEvent{
+		LTime:   1,
+		Name:    "first",
+		Payload: []byte("test"),
+	}
+	if !s.handleUserEvent(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+	msg = messageUserEvent{
+		LTime:   1,
+		Name:    "first",
+		Payload: []byte("newpayload"),
+	}
+	if !s.handleUserEvent(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+	msg = messageUserEvent{
+		LTime:   1,
+		Name:    "second",
+		Payload: []byte("other"),
+	}
+	if !s.handleUserEvent(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+
+	testUserEvents(t, eventCh,
+		[]string{"first", "first", "second"},
+		[][]byte{[]byte("test"), []byte("newpayload"), []byte("other")})
+}
+
+func TestSerf_query_oldMessage(t *testing.T) {
+	c := testConfig()
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	// increase the ltime artificially
+	s.queryClock.Witness(LamportTime(c.QueryBuffer + 1000))
+
+	msg := messageQuery{
+		LTime:   1,
+		Name:    "old",
+		Payload: nil,
+	}
+	if s.handleQuery(&msg) {
+		t.Fatalf("should not rebroadcast")
+	}
+}
+
+func TestSerf_query_sameClock(t *testing.T) {
+	eventCh := make(chan Event, 4)
+	c := testConfig()
+	c.EventCh = eventCh
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	msg := messageQuery{
+		LTime:   1,
+		ID:      1,
+		Name:    "foo",
+		Payload: []byte("test"),
+	}
+	if !s.handleQuery(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+	if s.handleQuery(&msg) {
+		t.Fatalf("should not rebroadcast")
+	}
+	msg = messageQuery{
+		LTime:   1,
+		ID:      2,
+		Name:    "bar",
+		Payload: []byte("newpayload"),
+	}
+	if !s.handleQuery(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+	if s.handleQuery(&msg) {
+		t.Fatalf("should not rebroadcast")
+	}
+	msg = messageQuery{
+		LTime:   1,
+		ID:      3,
+		Name:    "baz",
+		Payload: []byte("other"),
+	}
+	if !s.handleQuery(&msg) {
+		t.Fatalf("should rebroadcast")
+	}
+	if s.handleQuery(&msg) {
+		t.Fatalf("should not rebroadcast")
+	}
+
+	testQueryEvents(t, eventCh,
+		[]string{"foo", "bar", "baz"},
+		[][]byte{[]byte("test"), []byte("newpayload"), []byte("other")})
+}

+ 1647 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/serf_test.go

@@ -0,0 +1,1647 @@
+package serf
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/memberlist"
+	"github.com/hashicorp/serf/testutil"
+)
+
+func testConfig() *Config {
+	config := DefaultConfig()
+	config.Init()
+	config.MemberlistConfig.BindAddr = testutil.GetBindAddr().String()
+
+	// Set probe intervals that are aggressive for finding bad nodes
+	config.MemberlistConfig.GossipInterval = 5 * time.Millisecond
+	config.MemberlistConfig.ProbeInterval = 50 * time.Millisecond
+	config.MemberlistConfig.ProbeTimeout = 25 * time.Millisecond
+	config.MemberlistConfig.SuspicionMult = 1
+
+	config.NodeName = fmt.Sprintf("Node %s", config.MemberlistConfig.BindAddr)
+
+	// Set a short reap interval so that it can run during the test
+	config.ReapInterval = 1 * time.Second
+
+	// Set a short reconnect interval so that it can run a lot during tests
+	config.ReconnectInterval = 100 * time.Millisecond
+
+	// Set basically zero on the reconnect/tombstone timeouts so that
+	// they're removed on the first ReapInterval.
+	config.ReconnectTimeout = 1 * time.Microsecond
+	config.TombstoneTimeout = 1 * time.Microsecond
+
+	return config
+}
+
+// testMember tests that a member in a list is in a given state.
+func testMember(t *testing.T, members []Member, name string, status MemberStatus) {
+	for _, m := range members {
+		if m.Name == name {
+			if m.Status != status {
+				panic(fmt.Sprintf("bad state for %s: %d", name, m.Status))
+			}
+			return
+		}
+	}
+
+	if status == StatusNone {
+		// We didn't expect to find it
+		return
+	}
+
+	panic(fmt.Sprintf("node not found: %s", name))
+}
+
+func TestCreate_badProtocolVersion(t *testing.T) {
+	cases := []struct {
+		version uint8
+		err     bool
+	}{
+		{ProtocolVersionMin, false},
+		{ProtocolVersionMax, false},
+		// TODO(mitchellh): uncommon when we're over 0
+		//{ProtocolVersionMin - 1, true},
+		{ProtocolVersionMax + 1, true},
+		{ProtocolVersionMax - 1, false},
+	}
+
+	for _, tc := range cases {
+		c := testConfig()
+		c.ProtocolVersion = tc.version
+		s, err := Create(c)
+		if tc.err && err == nil {
+			t.Errorf("Should've failed with version: %d", tc.version)
+		} else if !tc.err && err != nil {
+			t.Errorf("Version '%d' error: %s", tc.version, err)
+		}
+
+		if err == nil {
+			s.Shutdown()
+		}
+	}
+}
+
+func TestSerf_eventsFailed(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(1 * time.Second)
+
+	// Since s2 shutdown, we check the events to make sure we got failures.
+	testEvents(t, eventCh, s2Config.NodeName,
+		[]EventType{EventMemberJoin, EventMemberFailed, EventMemberReap})
+}
+
+func TestSerf_eventsJoin(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	testEvents(t, eventCh, s2Config.NodeName,
+		[]EventType{EventMemberJoin})
+}
+
+func TestSerf_eventsLeave(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if err := s2.Leave(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Now that s2 has left, we check the events to make sure we got
+	// a leave event in s1 about the leave.
+	testEvents(t, eventCh, s2Config.NodeName,
+		[]EventType{EventMemberJoin, EventMemberLeave})
+}
+
+func TestSerf_eventsUser(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s2Config.EventCh = eventCh
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Fire a user event
+	if err := s1.UserEvent("event!", []byte("test"), false); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Fire a user event
+	if err := s1.UserEvent("second", []byte("foobar"), false); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// check the events to make sure we got
+	// a leave event in s1 about the leave.
+	testUserEvents(t, eventCh,
+		[]string{"event!", "second"},
+		[][]byte{[]byte("test"), []byte("foobar")})
+}
+
+func TestSerf_eventsUser_sizeLimit(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	s1Config := testConfig()
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	name := "this is too large an event"
+	payload := make([]byte, UserEventSizeLimit)
+	err = s1.UserEvent(name, payload, false)
+	if err == nil {
+		t.Fatalf("expect error")
+	}
+	if !strings.HasPrefix(err.Error(), "user event exceeds limit of ") {
+		t.Fatalf("should get size limit error")
+	}
+}
+
+func TestSerf_joinLeave(t *testing.T) {
+	s1Config := testConfig()
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	if len(s1.Members()) != 1 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 1 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if len(s1.Members()) != 2 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 2 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+
+	err = s1.Leave()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Give the reaper time to reap nodes
+	time.Sleep(s1Config.ReapInterval * 2)
+
+	if len(s1.Members()) != 1 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 1 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+}
+
+// Bug: GH-58
+func TestSerf_leaveRejoinDifferentRole(t *testing.T) {
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s2Config.Tags["role"] = "foo"
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	err = s2.Leave()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Make s3 look just like s2, but create a new node with a new role
+	s3Config := testConfig()
+	s3Config.MemberlistConfig.BindAddr = s2Config.MemberlistConfig.BindAddr
+	s3Config.NodeName = s2Config.NodeName
+	s3Config.Tags["role"] = "bar"
+
+	s3, err := Create(s3Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s3.Shutdown()
+
+	_, err = s3.Join([]string{s1Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	members := s1.Members()
+	if len(members) != 2 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	var member *Member = nil
+	for _, m := range members {
+		if m.Name == s3Config.NodeName {
+			member = &m
+			break
+		}
+	}
+
+	if member == nil {
+		t.Fatalf("couldn't find member")
+	}
+
+	if member.Tags["role"] != s3Config.Tags["role"] {
+		t.Fatalf("bad role: %s", member.Tags["role"])
+	}
+}
+
+func TestSerf_reconnect(t *testing.T) {
+	eventCh := make(chan Event, 64)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+
+	s2Config := testConfig()
+	s2Addr := s2Config.MemberlistConfig.BindAddr
+	s2Name := s2Config.NodeName
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Now force the shutdown of s2 so it appears to fail.
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(s2Config.MemberlistConfig.ProbeInterval * 5)
+
+	// Bring back s2 by mimicking its name and address
+	s2Config = testConfig()
+	s2Config.MemberlistConfig.BindAddr = s2Addr
+	s2Config.NodeName = s2Name
+	s2, err = Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(s1Config.ReconnectInterval * 5)
+
+	testEvents(t, eventCh, s2Name,
+		[]EventType{EventMemberJoin, EventMemberFailed, EventMemberJoin})
+}
+
+func TestSerf_reconnect_sameIP(t *testing.T) {
+	eventCh := make(chan Event, 64)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+
+	s2Config := testConfig()
+	s2Config.MemberlistConfig.BindAddr = s1Config.MemberlistConfig.BindAddr
+	s2Config.MemberlistConfig.BindPort = s1Config.MemberlistConfig.BindPort + 1
+
+	s2Addr := fmt.Sprintf("%s:%d",
+		s2Config.MemberlistConfig.BindAddr,
+		s2Config.MemberlistConfig.BindPort)
+	s2Name := s2Config.NodeName
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Addr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Now force the shutdown of s2 so it appears to fail.
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(s2Config.MemberlistConfig.ProbeInterval * 5)
+
+	// Bring back s2 by mimicking its name and address
+	s2Config = testConfig()
+	s2Config.MemberlistConfig.BindAddr = s1Config.MemberlistConfig.BindAddr
+	s2Config.MemberlistConfig.BindPort = s1Config.MemberlistConfig.BindPort + 1
+	s2Config.NodeName = s2Name
+	s2, err = Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(s1Config.ReconnectInterval * 5)
+
+	testEvents(t, eventCh, s2Name,
+		[]EventType{EventMemberJoin, EventMemberFailed, EventMemberJoin})
+}
+
+func TestSerf_role(t *testing.T) {
+	s1Config := testConfig()
+	s2Config := testConfig()
+
+	s1Config.Tags["role"] = "web"
+	s2Config.Tags["role"] = "lb"
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	members := s1.Members()
+	if len(members) != 2 {
+		t.Fatalf("should have 2 members")
+	}
+
+	roles := make(map[string]string)
+	for _, m := range members {
+		roles[m.Name] = m.Tags["role"]
+	}
+
+	if roles[s1Config.NodeName] != "web" {
+		t.Fatalf("bad role for web: %s", roles[s1Config.NodeName])
+	}
+
+	if roles[s2Config.NodeName] != "lb" {
+		t.Fatalf("bad role for lb: %s", roles[s2Config.NodeName])
+	}
+}
+
+func TestSerfProtocolVersion(t *testing.T) {
+	config := testConfig()
+	config.ProtocolVersion = ProtocolVersionMax
+
+	s1, err := Create(config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	actual := s1.ProtocolVersion()
+	if actual != ProtocolVersionMax {
+		t.Fatalf("bad: %#v", actual)
+	}
+}
+
+func TestSerfRemoveFailedNode(t *testing.T) {
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s3Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s3, err := Create(s3Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+	defer s3.Shutdown()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	_, err = s1.Join([]string{s3Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Now force the shutdown of s2 so it appears to fail.
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	time.Sleep(s2Config.MemberlistConfig.ProbeInterval * 5)
+
+	// Verify that s2 is "failed"
+	testMember(t, s1.Members(), s2Config.NodeName, StatusFailed)
+
+	// Now remove the failed node
+	if err := s1.RemoveFailedNode(s2Config.NodeName); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify that s2 is gone
+	testMember(t, s1.Members(), s2Config.NodeName, StatusLeft)
+	testMember(t, s3.Members(), s2Config.NodeName, StatusLeft)
+}
+
+func TestSerfRemoveFailedNode_ourself(t *testing.T) {
+	s1Config := testConfig()
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	testutil.Yield()
+
+	if err := s1.RemoveFailedNode("somebody"); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+}
+
+func TestSerfState(t *testing.T) {
+	s1, err := Create(testConfig())
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	if s1.State() != SerfAlive {
+		t.Fatalf("bad state: %d", s1.State())
+	}
+
+	if err := s1.Leave(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if s1.State() != SerfLeft {
+		t.Fatalf("bad state: %d", s1.State())
+	}
+
+	if err := s1.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if s1.State() != SerfShutdown {
+		t.Fatalf("bad state: %d", s1.State())
+	}
+}
+
+func TestSerf_ReapHandler_Shutdown(t *testing.T) {
+	s, err := Create(testConfig())
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	go func() {
+		s.Shutdown()
+		time.Sleep(time.Millisecond)
+		t.Fatalf("timeout")
+	}()
+	s.handleReap()
+}
+
+func TestSerf_ReapHandler(t *testing.T) {
+	c := testConfig()
+	c.ReapInterval = time.Nanosecond
+	c.TombstoneTimeout = time.Second * 6
+	s, err := Create(c)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	m := Member{}
+	s.leftMembers = []*memberState{
+		&memberState{m, 0, time.Now()},
+		&memberState{m, 0, time.Now().Add(-5 * time.Second)},
+		&memberState{m, 0, time.Now().Add(-10 * time.Second)},
+	}
+
+	go func() {
+		time.Sleep(time.Millisecond)
+		s.Shutdown()
+	}()
+
+	s.handleReap()
+
+	if len(s.leftMembers) != 2 {
+		t.Fatalf("should be shorter")
+	}
+}
+
+func TestSerf_Reap(t *testing.T) {
+	s, err := Create(testConfig())
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s.Shutdown()
+
+	m := Member{}
+	old := []*memberState{
+		&memberState{m, 0, time.Now()},
+		&memberState{m, 0, time.Now().Add(-5 * time.Second)},
+		&memberState{m, 0, time.Now().Add(-10 * time.Second)},
+	}
+
+	old = s.reap(old, time.Second*6)
+	if len(old) != 2 {
+		t.Fatalf("should be shorter")
+	}
+}
+
+func TestRemoveOldMember(t *testing.T) {
+	old := []*memberState{
+		&memberState{Member: Member{Name: "foo"}},
+		&memberState{Member: Member{Name: "bar"}},
+		&memberState{Member: Member{Name: "baz"}},
+	}
+
+	old = removeOldMember(old, "bar")
+	if len(old) != 2 {
+		t.Fatalf("should be shorter")
+	}
+	if old[1].Name == "bar" {
+		t.Fatalf("should remove old member")
+	}
+}
+
+func TestRecentIntent(t *testing.T) {
+	if recentIntent(nil, "foo") != nil {
+		t.Fatalf("should get nil on empty recent")
+	}
+	if recentIntent([]nodeIntent{}, "foo") != nil {
+		t.Fatalf("should get nil on empty recent")
+	}
+
+	recent := []nodeIntent{
+		nodeIntent{1, "foo"},
+		nodeIntent{2, "bar"},
+		nodeIntent{3, "baz"},
+		nodeIntent{4, "bar"},
+		nodeIntent{0, "bar"},
+		nodeIntent{5, "bar"},
+	}
+
+	if r := recentIntent(recent, "bar"); r.LTime != 4 {
+		t.Fatalf("bad time for bar")
+	}
+
+	if r := recentIntent(recent, "tubez"); r != nil {
+		t.Fatalf("got result for tubez")
+	}
+}
+
+func TestMemberStatus_String(t *testing.T) {
+	status := []MemberStatus{StatusNone, StatusAlive, StatusLeaving, StatusLeft, StatusFailed}
+	expect := []string{"none", "alive", "leaving", "left", "failed"}
+
+	for idx, s := range status {
+		if s.String() != expect[idx] {
+			t.Fatalf("got string %v, expected %v", s.String(), expect[idx])
+		}
+	}
+
+	other := MemberStatus(100)
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatalf("expected panic")
+		}
+	}()
+	other.String()
+}
+
+func TestSerf_joinLeaveJoin(t *testing.T) {
+	s1Config := testConfig()
+	s1Config.ReapInterval = 10 * time.Second
+	s2Config := testConfig()
+	s2Config.ReapInterval = 10 * time.Second
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if len(s1.Members()) != 1 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 1 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if len(s1.Members()) != 2 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 2 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+
+	// Leave and shutdown
+	err = s2.Leave()
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	s2.Shutdown()
+
+	// Give the reaper time to reap nodes
+	time.Sleep(s1Config.MemberlistConfig.ProbeInterval * 5)
+
+	// s1 should see the node as having left
+	mems := s1.Members()
+	anyLeft := false
+	for _, m := range mems {
+		if m.Status == StatusLeft {
+			anyLeft = true
+			break
+		}
+	}
+	if !anyLeft {
+		t.Fatalf("node should have left!")
+	}
+
+	// Bring node 2 back
+	s2, err = Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	// Re-attempt the join
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Should be back to both members
+	if len(s1.Members()) != 2 {
+		t.Fatalf("s1 members: %d", len(s1.Members()))
+	}
+
+	if len(s2.Members()) != 2 {
+		t.Fatalf("s2 members: %d", len(s2.Members()))
+	}
+
+	// s1 should see the node as alive
+	mems = s1.Members()
+	anyLeft = false
+	for _, m := range mems {
+		if m.Status == StatusLeft {
+			anyLeft = true
+			break
+		}
+	}
+	if anyLeft {
+		t.Fatalf("all nodes should be alive!")
+	}
+}
+
+func TestSerf_Join_IgnoreOld(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s2Config.EventCh = eventCh
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	// Fire a user event
+	if err := s1.UserEvent("event!", []byte("test"), false); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Fire a user event
+	if err := s1.UserEvent("second", []byte("foobar"), false); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// join with ignoreOld set to true! should not get events
+	_, err = s2.Join([]string{s1Config.MemberlistConfig.BindAddr}, true)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// check the events to make sure we got nothing
+	testUserEvents(t, eventCh, []string{}, [][]byte{})
+}
+
+func TestSerf_SnapshotRecovery(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s2Config.SnapshotPath = td + "snap"
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Fire a user event
+	if err := s1.UserEvent("event!", []byte("test"), false); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Now force the shutdown of s2 so it appears to fail.
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	time.Sleep(s2Config.MemberlistConfig.ProbeInterval * 10)
+
+	// Verify that s2 is "failed"
+	testMember(t, s1.Members(), s2Config.NodeName, StatusFailed)
+
+	// Now remove the failed node
+	if err := s1.RemoveFailedNode(s2Config.NodeName); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	// Verify that s2 is gone
+	testMember(t, s1.Members(), s2Config.NodeName, StatusLeft)
+
+	// Listen for events
+	eventCh := make(chan Event, 4)
+	s2Config.EventCh = eventCh
+
+	// Restart s2 from the snapshot now!
+	s2, err = Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	// Wait for the node to auto rejoin
+	start := time.Now()
+	for time.Now().Sub(start) < time.Second {
+		members := s1.Members()
+		if len(members) == 2 && members[0].Status == StatusAlive && members[1].Status == StatusAlive {
+			break
+		}
+		time.Sleep(10 * time.Millisecond)
+	}
+
+	// Verify that s2 is "alive"
+	testMember(t, s1.Members(), s2Config.NodeName, StatusAlive)
+	testMember(t, s2.Members(), s1Config.NodeName, StatusAlive)
+
+	// Check the events to make sure we got nothing
+	testUserEvents(t, eventCh, []string{}, [][]byte{})
+}
+
+func TestSerf_Leave_SnapshotRecovery(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s2Config.SnapshotPath = td + "snap"
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if err := s2.Leave(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	if err := s2.Shutdown(); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	time.Sleep(s2Config.MemberlistConfig.ProbeInterval * 5)
+
+	// Verify that s2 is "left"
+	testMember(t, s1.Members(), s2Config.NodeName, StatusLeft)
+
+	// Restart s2 from the snapshot now!
+	s2Config.EventCh = nil
+	s2, err = Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	// Wait for the node to auto rejoin
+	testutil.Yield()
+
+	// Verify that s2 is didn't join
+	testMember(t, s1.Members(), s2Config.NodeName, StatusLeft)
+	if len(s2.Members()) != 1 {
+		t.Fatalf("bad members: %#v", s2.Members())
+	}
+}
+
+func TestSerf_SetTags(t *testing.T) {
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+	s2Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	testutil.Yield()
+
+	// Update the tags
+	if err := s1.SetTags(map[string]string{"port": "8000"}); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	if err := s2.SetTags(map[string]string{"datacenter": "east-aws"}); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	testutil.Yield()
+
+	// Since s2 shutdown, we check the events to make sure we got failures.
+	testEvents(t, eventCh, s2Config.NodeName,
+		[]EventType{EventMemberJoin, EventMemberUpdate})
+
+	// Verify the new tags
+	m1m := s1.Members()
+	m1m_tags := make(map[string]map[string]string)
+	for _, m := range m1m {
+		m1m_tags[m.Name] = m.Tags
+	}
+
+	if m := m1m_tags[s1.config.NodeName]; m["port"] != "8000" {
+		t.Fatalf("bad: %v", m1m_tags)
+	}
+
+	if m := m1m_tags[s2.config.NodeName]; m["datacenter"] != "east-aws" {
+		t.Fatalf("bad: %v", m1m_tags)
+	}
+
+	m2m := s2.Members()
+	m2m_tags := make(map[string]map[string]string)
+	for _, m := range m2m {
+		m2m_tags[m.Name] = m.Tags
+	}
+
+	if m := m2m_tags[s1.config.NodeName]; m["port"] != "8000" {
+		t.Fatalf("bad: %v", m1m_tags)
+	}
+
+	if m := m2m_tags[s2.config.NodeName]; m["datacenter"] != "east-aws" {
+		t.Fatalf("bad: %v", m1m_tags)
+	}
+}
+
+func TestSerf_Query(t *testing.T) {
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	// Listen for the query
+	go func() {
+		for {
+			select {
+			case e := <-eventCh:
+				if e.EventType() != EventQuery {
+					continue
+				}
+				q := e.(*Query)
+				if err := q.Respond([]byte("test")); err != nil {
+					t.Fatalf("err: %s", err)
+				}
+				return
+			case <-time.After(time.Second):
+				t.Fatalf("timeout")
+			}
+		}
+	}()
+
+	s2Config := testConfig()
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	testutil.Yield()
+
+	// Start a query from s2
+	params := s2.DefaultQueryParams()
+	params.RequestAck = true
+	resp, err := s2.Query("load", []byte("sup girl"), params)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	var acks []string
+	var responses []string
+
+	ackCh := resp.AckCh()
+	respCh := resp.ResponseCh()
+	for i := 0; i < 3; i++ {
+		select {
+		case a := <-ackCh:
+			acks = append(acks, a)
+
+		case r := <-respCh:
+			if r.From != s1Config.NodeName {
+				t.Fatalf("bad: %v", r)
+			}
+			if string(r.Payload) != "test" {
+				t.Fatalf("bad: %v", r)
+			}
+			responses = append(responses, r.From)
+
+		case <-time.After(time.Second):
+			t.Fatalf("timeout")
+		}
+	}
+
+	if len(acks) != 2 {
+		t.Fatalf("missing acks: %v", acks)
+	}
+	if len(responses) != 1 {
+		t.Fatalf("missing responses: %v", responses)
+	}
+}
+
+func TestSerf_Query_Filter(t *testing.T) {
+	eventCh := make(chan Event, 4)
+	s1Config := testConfig()
+	s1Config.EventCh = eventCh
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	// Listen for the query
+	go func() {
+		for {
+			select {
+			case e := <-eventCh:
+				if e.EventType() != EventQuery {
+					continue
+				}
+				q := e.(*Query)
+				if err := q.Respond([]byte("test")); err != nil {
+					t.Fatalf("err: %s", err)
+				}
+				return
+			case <-time.After(time.Second):
+				t.Fatalf("timeout")
+			}
+		}
+	}()
+
+	s2Config := testConfig()
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	testutil.Yield()
+
+	// Filter to only s1!
+	params := s2.DefaultQueryParams()
+	params.FilterNodes = []string{s1Config.NodeName}
+	params.RequestAck = true
+
+	// Start a query from s2
+	resp, err := s2.Query("load", []byte("sup girl"), params)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	var acks []string
+	var responses []string
+
+	ackCh := resp.AckCh()
+	respCh := resp.ResponseCh()
+	for i := 0; i < 2; i++ {
+		select {
+		case a := <-ackCh:
+			acks = append(acks, a)
+
+		case r := <-respCh:
+			if r.From != s1Config.NodeName {
+				t.Fatalf("bad: %v", r)
+			}
+			if string(r.Payload) != "test" {
+				t.Fatalf("bad: %v", r)
+			}
+			responses = append(responses, r.From)
+
+		case <-time.After(time.Second):
+			t.Fatalf("timeout")
+		}
+	}
+
+	if len(acks) != 1 {
+		t.Fatalf("missing acks: %v", acks)
+	}
+	if len(responses) != 1 {
+		t.Fatalf("missing responses: %v", responses)
+	}
+}
+
+func TestSerf_Query_sizeLimit(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	s1Config := testConfig()
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	name := "this is too large a query"
+	payload := make([]byte, QuerySizeLimit)
+	_, err = s1.Query(name, payload, nil)
+	if err == nil {
+		t.Fatalf("should get error")
+	}
+	if !strings.HasPrefix(err.Error(), "query exceeds limit of ") {
+		t.Fatalf("should get size limit error: %v", err)
+	}
+}
+
+func TestSerf_NameResolution(t *testing.T) {
+	// Create the s1 config with an event channel so we can listen
+	s1Config := testConfig()
+	s2Config := testConfig()
+	s3Config := testConfig()
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s2.Shutdown()
+
+	// Create an artificial node name conflict!
+	s3Config.NodeName = s1Config.NodeName
+	s3, err := Create(s3Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s3.Shutdown()
+
+	testutil.Yield()
+
+	// Join s1 to s2 first. s2 should vote for s1 in conflict
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	_, err = s1.Join([]string{s3Config.MemberlistConfig.BindAddr}, false)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	// Wait for the query period to end
+	time.Sleep(s1.DefaultQueryTimeout() * 2)
+
+	// s3 should have shutdown, while s1 is running
+	if s1.State() != SerfAlive {
+		t.Fatalf("bad: %v", s1.State())
+	}
+	if s2.State() != SerfAlive {
+		t.Fatalf("bad: %v", s2.State())
+	}
+	if s3.State() != SerfShutdown {
+		t.Fatalf("bad: %v", s3.State())
+	}
+}
+
+func TestSerf_LocalMember(t *testing.T) {
+	s1Config := testConfig()
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	m := s1.LocalMember()
+	if m.Name != s1Config.NodeName {
+		t.Fatalf("bad: %v", m)
+	}
+	if !reflect.DeepEqual(m.Tags, s1Config.Tags) {
+		t.Fatalf("bad: %v", m)
+	}
+	if m.Status != StatusAlive {
+		t.Fatalf("bad: %v", m)
+	}
+
+	newTags := map[string]string{
+		"foo":  "bar",
+		"test": "ing",
+	}
+	if err := s1.SetTags(newTags); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	m = s1.LocalMember()
+	if !reflect.DeepEqual(m.Tags, newTags) {
+		t.Fatalf("bad: %v", m)
+	}
+}
+
+func TestSerf_WriteKeyringFile(t *testing.T) {
+	existing := "jbuQMI4gMUeh1PPmKOtiBg=="
+	newKey := "eodFZZjm7pPwIZ0Miy7boQ=="
+
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer os.RemoveAll(td)
+
+	keyringFile := filepath.Join(td, "tags.json")
+
+	existingBytes, err := base64.StdEncoding.DecodeString(existing)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	keys := [][]byte{existingBytes}
+	keyring, err := memberlist.NewKeyring(keys, existingBytes)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s1Config := testConfig()
+	s1Config.MemberlistConfig.Keyring = keyring
+	s1Config.KeyringFile = keyringFile
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	manager := s1.KeyManager()
+
+	if _, err := manager.InstallKey(newKey); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	content, err := ioutil.ReadFile(keyringFile)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	lines := strings.Split(string(content), "\n")
+	if len(lines) != 4 {
+		t.Fatalf("bad: %v", lines)
+	}
+
+	// Ensure both the original key and the new key are present in the file
+	if !strings.Contains(string(content), existing) {
+		t.Fatalf("key not found in keyring file: %s", existing)
+	}
+	if !strings.Contains(string(content), newKey) {
+		t.Fatalf("key not found in keyring file: %s", newKey)
+	}
+
+	// Ensure the existing key remains primary. This is in position 1 because
+	// the file writer will use json.MarshalIndent(), leaving the first line as
+	// the opening bracket.
+	if !strings.Contains(lines[1], existing) {
+		t.Fatalf("expected key to be primary: %s", existing)
+	}
+
+	// Swap primary keys
+	if _, err := manager.UseKey(newKey); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	content, err = ioutil.ReadFile(keyringFile)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	lines = strings.Split(string(content), "\n")
+	if len(lines) != 4 {
+		t.Fatalf("bad: %v", lines)
+	}
+
+	// Key order should have changed in keyring file
+	if !strings.Contains(lines[1], newKey) {
+		t.Fatalf("expected key to be primary: %s", newKey)
+	}
+
+	// Remove the old key
+	if _, err := manager.RemoveKey(existing); err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	content, err = ioutil.ReadFile(keyringFile)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	lines = strings.Split(string(content), "\n")
+	if len(lines) != 3 {
+		t.Fatalf("bad: %v", lines)
+	}
+
+	// Only the new key should now be present in the keyring file
+	if len(lines) != 3 {
+		t.Fatalf("bad: %v", lines)
+	}
+	if !strings.Contains(lines[1], newKey) {
+		t.Fatalf("expected key to be primary: %s", newKey)
+	}
+}
+
+func TestSerfStats(t *testing.T) {
+	config := testConfig()
+	s1, err := Create(config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+	defer s1.Shutdown()
+
+	stats := s1.Stats()
+
+	expected := map[string]string{
+		"event_queue":  "0",
+		"event_time":   "1",
+		"failed":       "0",
+		"intent_queue": "0",
+		"left":         "0",
+		"member_time":  "1",
+		"members":      "1",
+		"query_queue":  "0",
+		"query_time":   "1",
+		"encrypted":    "false",
+	}
+
+	for key, val := range expected {
+		v, ok := stats[key]
+		if !ok {
+			t.Fatalf("key not found in stats: %s", key)
+		}
+		if v != val {
+			t.Fatalf("bad: %s = %s", key, val)
+		}
+	}
+}
+
+type CancelMergeDelegate struct {
+	invoked bool
+}
+
+func (c *CancelMergeDelegate) NotifyMerge(members []*Member) (cancel bool) {
+	log.Printf("Merge canceled")
+	c.invoked = true
+	return true
+}
+
+func TestSerf_Join_Cancel(t *testing.T) {
+	s1Config := testConfig()
+	merge1 := &CancelMergeDelegate{}
+	s1Config.Merge = merge1
+
+	s2Config := testConfig()
+	merge2 := &CancelMergeDelegate{}
+	s2Config.Merge = merge2
+
+	s1, err := Create(s1Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	s2, err := Create(s2Config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	defer s1.Shutdown()
+	defer s2.Shutdown()
+
+	testutil.Yield()
+
+	_, err = s1.Join([]string{s2Config.MemberlistConfig.BindAddr}, false)
+	if err.Error() != "Merge canceled" {
+		t.Fatalf("err: %s", err)
+	}
+
+	testutil.Yield()
+
+	if !merge1.invoked {
+		t.Fatalf("should invoke")
+	}
+	if !merge2.invoked {
+		t.Fatalf("should invoke")
+	}
+}

+ 500 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/snapshot.go

@@ -0,0 +1,500 @@
+package serf
+
+import (
+	"bufio"
+	"fmt"
+	"log"
+	"math/rand"
+	"net"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/armon/go-metrics"
+)
+
+/*
+Serf supports using a "snapshot" file that contains various
+transactional data that is used to help Serf recover quickly
+and gracefully from a failure. We append member events, as well
+as the latest clock values to the file during normal operation,
+and periodically checkpoint and roll over the file. During a restore,
+we can replay the various member events to recall a list of known
+nodes to re-join, as well as restore our clock values to avoid replaying
+old events.
+*/
+
+const flushInterval = 500 * time.Millisecond
+const clockUpdateInterval = 500 * time.Millisecond
+const tmpExt = ".compact"
+
+// Snapshotter is responsible for ingesting events and persisting
+// them to disk, and providing a recovery mechanism at start time.
+type Snapshotter struct {
+	aliveNodes       map[string]string
+	clock            *LamportClock
+	fh               *os.File
+	buffered         *bufio.Writer
+	inCh             <-chan Event
+	lastFlush        time.Time
+	lastClock        LamportTime
+	lastEventClock   LamportTime
+	lastQueryClock   LamportTime
+	leaveCh          chan struct{}
+	leaving          bool
+	logger           *log.Logger
+	maxSize          int64
+	path             string
+	offset           int64
+	outCh            chan<- Event
+	rejoinAfterLeave bool
+	shutdownCh       <-chan struct{}
+	waitCh           chan struct{}
+}
+
+// PreviousNode is used to represent the previously known alive nodes
+type PreviousNode struct {
+	Name string
+	Addr string
+}
+
+func (p PreviousNode) String() string {
+	return fmt.Sprintf("%s: %s", p.Name, p.Addr)
+}
+
+// NewSnapshotter creates a new Snapshotter that records events up to a
+// max byte size before rotating the file. It can also be used to
+// recover old state. Snapshotter works by reading an event channel it returns,
+// passing through to an output channel, and persisting relevant events to disk.
+// Setting rejoinAfterLeave makes leave not clear the state, and can be used
+// if you intend to rejoin the same cluster after a leave.
+func NewSnapshotter(path string,
+	maxSize int,
+	rejoinAfterLeave bool,
+	logger *log.Logger,
+	clock *LamportClock,
+	outCh chan<- Event,
+	shutdownCh <-chan struct{}) (chan<- Event, *Snapshotter, error) {
+	inCh := make(chan Event, 1024)
+
+	// Try to open the file
+	fh, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to open snapshot: %v", err)
+	}
+
+	// Determine the offset
+	info, err := fh.Stat()
+	if err != nil {
+		fh.Close()
+		return nil, nil, fmt.Errorf("failed to stat snapshot: %v", err)
+	}
+	offset := info.Size()
+
+	// Create the snapshotter
+	snap := &Snapshotter{
+		aliveNodes:       make(map[string]string),
+		clock:            clock,
+		fh:               fh,
+		buffered:         bufio.NewWriter(fh),
+		inCh:             inCh,
+		lastClock:        0,
+		lastEventClock:   0,
+		lastQueryClock:   0,
+		leaveCh:          make(chan struct{}),
+		logger:           logger,
+		maxSize:          int64(maxSize),
+		path:             path,
+		offset:           offset,
+		outCh:            outCh,
+		rejoinAfterLeave: rejoinAfterLeave,
+		shutdownCh:       shutdownCh,
+		waitCh:           make(chan struct{}),
+	}
+
+	// Recover the last known state
+	if err := snap.replay(); err != nil {
+		fh.Close()
+		return nil, nil, err
+	}
+
+	// Start handling new commands
+	go snap.stream()
+	return inCh, snap, nil
+}
+
+// LastClock returns the last known clock time
+func (s *Snapshotter) LastClock() LamportTime {
+	return s.lastClock
+}
+
+// LastEventClock returns the last known event clock time
+func (s *Snapshotter) LastEventClock() LamportTime {
+	return s.lastEventClock
+}
+
+// LastQueryClock returns the last known query clock time
+func (s *Snapshotter) LastQueryClock() LamportTime {
+	return s.lastQueryClock
+}
+
+// AliveNodes returns the last known alive nodes
+func (s *Snapshotter) AliveNodes() []*PreviousNode {
+	// Copy the previously known
+	previous := make([]*PreviousNode, 0, len(s.aliveNodes))
+	for name, addr := range s.aliveNodes {
+		previous = append(previous, &PreviousNode{name, addr})
+	}
+
+	// Randomize the order, prevents hot shards
+	for i := range previous {
+		j := rand.Intn(i + 1)
+		previous[i], previous[j] = previous[j], previous[i]
+	}
+	return previous
+}
+
+// Wait is used to wait until the snapshotter finishes shut down
+func (s *Snapshotter) Wait() {
+	<-s.waitCh
+}
+
+// Leave is used to remove known nodes to prevent a restart from
+// causing a join. Otherwise nodes will re-join after leaving!
+func (s *Snapshotter) Leave() {
+	select {
+	case s.leaveCh <- struct{}{}:
+	case <-s.shutdownCh:
+	}
+}
+
+// stream is a long running routine that is used to handle events
+func (s *Snapshotter) stream() {
+	for {
+		select {
+		case <-s.leaveCh:
+			s.leaving = true
+
+			// If we plan to re-join, keep our state
+			if !s.rejoinAfterLeave {
+				s.aliveNodes = make(map[string]string)
+			}
+			s.tryAppend("leave\n")
+			if err := s.buffered.Flush(); err != nil {
+				s.logger.Printf("[ERR] serf: failed to flush leave to snapshot: %v", err)
+			}
+			if err := s.fh.Sync(); err != nil {
+				s.logger.Printf("[ERR] serf: failed to sync leave to snapshot: %v", err)
+			}
+
+		case e := <-s.inCh:
+			// Forward the event immediately
+			if s.outCh != nil {
+				s.outCh <- e
+			}
+
+			// Stop recording events after a leave is issued
+			if s.leaving {
+				continue
+			}
+			switch typed := e.(type) {
+			case MemberEvent:
+				s.processMemberEvent(typed)
+			case UserEvent:
+				s.processUserEvent(typed)
+			case *Query:
+				s.processQuery(typed)
+			default:
+				s.logger.Printf("[ERR] serf: Unknown event to snapshot: %#v", e)
+			}
+
+		case <-time.After(clockUpdateInterval):
+			s.updateClock()
+
+		case <-s.shutdownCh:
+			if err := s.buffered.Flush(); err != nil {
+				s.logger.Printf("[ERR] serf: failed to flush snapshot: %v", err)
+			}
+			if err := s.fh.Sync(); err != nil {
+				s.logger.Printf("[ERR] serf: failed to sync snapshot: %v", err)
+			}
+			s.fh.Close()
+			close(s.waitCh)
+			return
+		}
+	}
+}
+
+// processMemberEvent is used to handle a single member event
+func (s *Snapshotter) processMemberEvent(e MemberEvent) {
+	switch e.Type {
+	case EventMemberJoin:
+		for _, mem := range e.Members {
+			addr := net.TCPAddr{IP: mem.Addr, Port: int(mem.Port)}
+			s.aliveNodes[mem.Name] = addr.String()
+			s.tryAppend(fmt.Sprintf("alive: %s %s\n", mem.Name, addr.String()))
+		}
+
+	case EventMemberLeave:
+		fallthrough
+	case EventMemberFailed:
+		for _, mem := range e.Members {
+			delete(s.aliveNodes, mem.Name)
+			s.tryAppend(fmt.Sprintf("not-alive: %s\n", mem.Name))
+		}
+	}
+	s.updateClock()
+}
+
+// updateClock is called periodically to check if we should udpate our
+// clock value. This is done after member events but should also be done
+// periodically due to race conditions with join and leave intents
+func (s *Snapshotter) updateClock() {
+	lastSeen := s.clock.Time() - 1
+	if lastSeen > s.lastClock {
+		s.lastClock = lastSeen
+		s.tryAppend(fmt.Sprintf("clock: %d\n", s.lastClock))
+	}
+}
+
+// processUserEvent is used to handle a single user event
+func (s *Snapshotter) processUserEvent(e UserEvent) {
+	// Ignore old clocks
+	if e.LTime <= s.lastEventClock {
+		return
+	}
+	s.lastEventClock = e.LTime
+	s.tryAppend(fmt.Sprintf("event-clock: %d\n", e.LTime))
+}
+
+// processQuery is used to handle a single query event
+func (s *Snapshotter) processQuery(q *Query) {
+	// Ignore old clocks
+	if q.LTime <= s.lastQueryClock {
+		return
+	}
+	s.lastQueryClock = q.LTime
+	s.tryAppend(fmt.Sprintf("query-clock: %d\n", q.LTime))
+}
+
+// tryAppend will invoke append line but will not return an error
+func (s *Snapshotter) tryAppend(l string) {
+	if err := s.appendLine(l); err != nil {
+		s.logger.Printf("[ERR] serf: Failed to update snapshot: %v", err)
+	}
+}
+
+// appendLine is used to append a line to the existing log
+func (s *Snapshotter) appendLine(l string) error {
+	defer metrics.MeasureSince([]string{"serf", "snapshot", "appendLine"}, time.Now())
+
+	n, err := s.buffered.WriteString(l)
+	if err != nil {
+		return err
+	}
+
+	// Check if we should flush
+	now := time.Now()
+	if now.Sub(s.lastFlush) > flushInterval {
+		s.lastFlush = now
+		if err := s.buffered.Flush(); err != nil {
+			return err
+		}
+	}
+
+	// Check if a compaction is necessary
+	s.offset += int64(n)
+	if s.offset > s.maxSize {
+		return s.compact()
+	}
+	return nil
+}
+
+// Compact is used to compact the snapshot once it is too large
+func (s *Snapshotter) compact() error {
+	defer metrics.MeasureSince([]string{"serf", "snapshot", "compact"}, time.Now())
+
+	// Try to open the file to new fiel
+	newPath := s.path + tmpExt
+	fh, err := os.OpenFile(newPath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0755)
+	if err != nil {
+		return fmt.Errorf("failed to open new snapshot: %v", err)
+	}
+
+	// Create a buffered writer
+	buf := bufio.NewWriter(fh)
+
+	// Write out the live nodes
+	var offset int64
+	for name, addr := range s.aliveNodes {
+		line := fmt.Sprintf("alive: %s %s\n", name, addr)
+		n, err := buf.WriteString(line)
+		if err != nil {
+			fh.Close()
+			return err
+		}
+		offset += int64(n)
+	}
+
+	// Write out the clocks
+	line := fmt.Sprintf("clock: %d\n", s.lastClock)
+	n, err := buf.WriteString(line)
+	if err != nil {
+		fh.Close()
+		return err
+	}
+	offset += int64(n)
+
+	line = fmt.Sprintf("event-clock: %d\n", s.lastEventClock)
+	n, err = buf.WriteString(line)
+	if err != nil {
+		fh.Close()
+		return err
+	}
+	offset += int64(n)
+
+	line = fmt.Sprintf("query-clock: %d\n", s.lastQueryClock)
+	n, err = buf.WriteString(line)
+	if err != nil {
+		fh.Close()
+		return err
+	}
+	offset += int64(n)
+
+	// Flush the new snapshot
+	err = buf.Flush()
+	fh.Close()
+	if err != nil {
+		return fmt.Errorf("failed to flush new snapshot: %v", err)
+	}
+
+	// We now need to swap the old snapshot file with the new snapshot.
+	// Turns out, Windows won't let us rename the files if we have
+	// open handles to them or if the destination already exists. This
+	// means we are forced to close the existing handles, delete the
+	// old file, move the new one in place, and then re-open the file
+	// handles.
+
+	// Flush the existing snapshot, ignoring errors since we will
+	// delete it momentarily.
+	s.buffered.Flush()
+	s.buffered = nil
+
+	// Close the file handle to the old snapshot
+	s.fh.Close()
+	s.fh = nil
+
+	// Delete the old file
+	if err := os.Remove(s.path); err != nil {
+		return fmt.Errorf("failed to remove old snapshot: %v", err)
+	}
+
+	// Move the new file into place
+	if err := os.Rename(newPath, s.path); err != nil {
+		return fmt.Errorf("failed to install new snapshot: %v", err)
+	}
+
+	// Open the new snapshot
+	fh, err = os.OpenFile(s.path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755)
+	if err != nil {
+		return fmt.Errorf("failed to open snapshot: %v", err)
+	}
+	buf = bufio.NewWriter(fh)
+
+	// Rotate our handles
+	s.fh = fh
+	s.buffered = buf
+	s.offset = offset
+	s.lastFlush = time.Now()
+	return nil
+}
+
+// replay is used to seek to reset our internal state by replaying
+// the snapshot file. It is used at initialization time to read old
+// state
+func (s *Snapshotter) replay() error {
+	// Seek to the beginning
+	if _, err := s.fh.Seek(0, os.SEEK_SET); err != nil {
+		return err
+	}
+
+	// Read each line
+	reader := bufio.NewReader(s.fh)
+	for {
+		line, err := reader.ReadString('\n')
+		if err != nil {
+			break
+		}
+
+		// Skip the newline
+		line = line[:len(line)-1]
+
+		// Switch on the prefix
+		if strings.HasPrefix(line, "alive: ") {
+			info := strings.TrimPrefix(line, "alive: ")
+			addrIdx := strings.LastIndex(info, " ")
+			if addrIdx == -1 {
+				s.logger.Printf("[WARN] serf: Failed to parse address: %v", line)
+				continue
+			}
+			addr := info[addrIdx+1:]
+			name := info[:addrIdx]
+			s.aliveNodes[name] = addr
+
+		} else if strings.HasPrefix(line, "not-alive: ") {
+			name := strings.TrimPrefix(line, "not-alive: ")
+			delete(s.aliveNodes, name)
+
+		} else if strings.HasPrefix(line, "clock: ") {
+			timeStr := strings.TrimPrefix(line, "clock: ")
+			timeInt, err := strconv.ParseUint(timeStr, 10, 64)
+			if err != nil {
+				s.logger.Printf("[WARN] serf: Failed to convert clock time: %v", err)
+				continue
+			}
+			s.lastClock = LamportTime(timeInt)
+
+		} else if strings.HasPrefix(line, "event-clock: ") {
+			timeStr := strings.TrimPrefix(line, "event-clock: ")
+			timeInt, err := strconv.ParseUint(timeStr, 10, 64)
+			if err != nil {
+				s.logger.Printf("[WARN] serf: Failed to convert event clock time: %v", err)
+				continue
+			}
+			s.lastEventClock = LamportTime(timeInt)
+
+		} else if strings.HasPrefix(line, "query-clock: ") {
+			timeStr := strings.TrimPrefix(line, "query-clock: ")
+			timeInt, err := strconv.ParseUint(timeStr, 10, 64)
+			if err != nil {
+				s.logger.Printf("[WARN] serf: Failed to convert query clock time: %v", err)
+				continue
+			}
+			s.lastQueryClock = LamportTime(timeInt)
+
+		} else if line == "leave" {
+			// Ignore a leave if we plan on re-joining
+			if s.rejoinAfterLeave {
+				s.logger.Printf("[INFO] serf: Ignoring previous leave in snapshot")
+				continue
+			}
+			s.aliveNodes = make(map[string]string)
+			s.lastClock = 0
+			s.lastEventClock = 0
+			s.lastQueryClock = 0
+
+		} else if strings.HasPrefix(line, "#") {
+			// Skip comment lines
+
+		} else {
+			s.logger.Printf("[WARN] serf: Unrecognized snapshot line: %v", line)
+		}
+	}
+
+	// Seek to the end
+	if _, err := s.fh.Seek(0, os.SEEK_END); err != nil {
+		return err
+	}
+	return nil
+}

+ 374 - 0
libnetwork/Godeps/_workspace/src/github.com/hashicorp/serf/serf/snapshot_test.go

@@ -0,0 +1,374 @@
+package serf
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestSnapshoter(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	clock := new(LamportClock)
+	outCh := make(chan Event, 64)
+	stopCh := make(chan struct{})
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	inCh, snap, err := NewSnapshotter(td+"snap", snapshotSizeLimit, false,
+		logger, clock, outCh, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Write some user events
+	ue := UserEvent{
+		LTime: 42,
+		Name:  "bar",
+	}
+	inCh <- ue
+
+	// Write some queries
+	q := &Query{
+		LTime: 50,
+		Name:  "uptime",
+	}
+	inCh <- q
+
+	// Write some member events
+	clock.Witness(100)
+	meJoin := MemberEvent{
+		Type: EventMemberJoin,
+		Members: []Member{
+			Member{
+				Name: "foo",
+				Addr: []byte{127, 0, 0, 1},
+				Port: 5000,
+			},
+		},
+	}
+	meFail := MemberEvent{
+		Type: EventMemberFailed,
+		Members: []Member{
+			Member{
+				Name: "foo",
+				Addr: []byte{127, 0, 0, 1},
+				Port: 5000,
+			},
+		},
+	}
+	inCh <- meJoin
+	inCh <- meFail
+	inCh <- meJoin
+
+	// Check these get passed through
+	select {
+	case e := <-outCh:
+		if !reflect.DeepEqual(e, ue) {
+			t.Fatalf("expected user event: %#v", e)
+		}
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+
+	select {
+	case e := <-outCh:
+		if !reflect.DeepEqual(e, q) {
+			t.Fatalf("expected query event: %#v", e)
+		}
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+
+	select {
+	case e := <-outCh:
+		if !reflect.DeepEqual(e, meJoin) {
+			t.Fatalf("expected member event: %#v", e)
+		}
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+
+	select {
+	case e := <-outCh:
+		if !reflect.DeepEqual(e, meFail) {
+			t.Fatalf("expected member event: %#v", e)
+		}
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+
+	select {
+	case e := <-outCh:
+		if !reflect.DeepEqual(e, meJoin) {
+			t.Fatalf("expected member event: %#v", e)
+		}
+	case <-time.After(200 * time.Millisecond):
+		t.Fatalf("timeout")
+	}
+
+	// Close the snapshoter
+	close(stopCh)
+	snap.Wait()
+
+	// Open the snapshoter
+	stopCh = make(chan struct{})
+	_, snap, err = NewSnapshotter(td+"snap", snapshotSizeLimit, false,
+		logger, clock, outCh, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Check the values
+	if snap.LastClock() != 100 {
+		t.Fatalf("bad clock %d", snap.LastClock())
+	}
+	if snap.LastEventClock() != 42 {
+		t.Fatalf("bad clock %d", snap.LastEventClock())
+	}
+	if snap.LastQueryClock() != 50 {
+		t.Fatalf("bad clock %d", snap.LastQueryClock())
+	}
+
+	prev := snap.AliveNodes()
+	if len(prev) != 1 {
+		t.Fatalf("expected alive: %#v", prev)
+	}
+	if prev[0].Name != "foo" {
+		t.Fatalf("bad name: %#v", prev[0])
+	}
+	if prev[0].Addr != "127.0.0.1:5000" {
+		t.Fatalf("bad addr: %#v", prev[0])
+	}
+}
+
+func TestSnapshoter_forceCompact(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	clock := new(LamportClock)
+	stopCh := make(chan struct{})
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+
+	// Create a very low limit
+	inCh, snap, err := NewSnapshotter(td+"snap", 1024, false,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Write lots of user events
+	for i := 0; i < 1024; i++ {
+		ue := UserEvent{
+			LTime: LamportTime(i),
+		}
+		inCh <- ue
+	}
+
+	// Write lots of queries
+	for i := 0; i < 1024; i++ {
+		q := &Query{
+			LTime: LamportTime(i),
+		}
+		inCh <- q
+	}
+
+	// Wait for drain
+	for len(inCh) > 0 {
+		time.Sleep(20 * time.Millisecond)
+	}
+
+	// Close the snapshoter
+	close(stopCh)
+	snap.Wait()
+
+	// Open the snapshoter
+	stopCh = make(chan struct{})
+	_, snap, err = NewSnapshotter(td+"snap", snapshotSizeLimit, false,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Check the values
+	if snap.LastEventClock() != 1023 {
+		t.Fatalf("bad clock %d", snap.LastEventClock())
+	}
+
+	if snap.LastQueryClock() != 1023 {
+		t.Fatalf("bad clock %d", snap.LastQueryClock())
+	}
+
+	close(stopCh)
+	snap.Wait()
+}
+
+func TestSnapshoter_leave(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	clock := new(LamportClock)
+	stopCh := make(chan struct{})
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	inCh, snap, err := NewSnapshotter(td+"snap", snapshotSizeLimit, false,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Write a user event
+	ue := UserEvent{
+		LTime: 42,
+		Name:  "bar",
+	}
+	inCh <- ue
+
+	// Write a query
+	q := &Query{
+		LTime: 50,
+		Name:  "uptime",
+	}
+	inCh <- q
+
+	// Write some member events
+	clock.Witness(100)
+	meJoin := MemberEvent{
+		Type: EventMemberJoin,
+		Members: []Member{
+			Member{
+				Name: "foo",
+				Addr: []byte{127, 0, 0, 1},
+				Port: 5000,
+			},
+		},
+	}
+	inCh <- meJoin
+
+	// Wait for drain
+	for len(inCh) > 0 {
+		time.Sleep(20 * time.Millisecond)
+	}
+
+	// Leave the cluster!
+	snap.Leave()
+
+	// Close the snapshoter
+	close(stopCh)
+	snap.Wait()
+
+	// Open the snapshoter
+	stopCh = make(chan struct{})
+	_, snap, err = NewSnapshotter(td+"snap", snapshotSizeLimit, false,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Check the values
+	if snap.LastClock() != 0 {
+		t.Fatalf("bad clock %d", snap.LastClock())
+	}
+	if snap.LastEventClock() != 0 {
+		t.Fatalf("bad clock %d", snap.LastEventClock())
+	}
+	if snap.LastQueryClock() != 0 {
+		t.Fatalf("bad clock %d", snap.LastQueryClock())
+	}
+
+	prev := snap.AliveNodes()
+	if len(prev) != 0 {
+		t.Fatalf("expected none alive: %#v", prev)
+	}
+}
+
+func TestSnapshoter_leave_rejoin(t *testing.T) {
+	td, err := ioutil.TempDir("", "serf")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	defer os.RemoveAll(td)
+
+	clock := new(LamportClock)
+	stopCh := make(chan struct{})
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	inCh, snap, err := NewSnapshotter(td+"snap", snapshotSizeLimit, true,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Write a user event
+	ue := UserEvent{
+		LTime: 42,
+		Name:  "bar",
+	}
+	inCh <- ue
+
+	// Write a query
+	q := &Query{
+		LTime: 50,
+		Name:  "uptime",
+	}
+	inCh <- q
+
+	// Write some member events
+	clock.Witness(100)
+	meJoin := MemberEvent{
+		Type: EventMemberJoin,
+		Members: []Member{
+			Member{
+				Name: "foo",
+				Addr: []byte{127, 0, 0, 1},
+				Port: 5000,
+			},
+		},
+	}
+	inCh <- meJoin
+
+	// Wait for drain
+	for len(inCh) > 0 {
+		time.Sleep(20 * time.Millisecond)
+	}
+
+	// Leave the cluster!
+	snap.Leave()
+
+	// Close the snapshoter
+	close(stopCh)
+	snap.Wait()
+
+	// Open the snapshoter
+	stopCh = make(chan struct{})
+	_, snap, err = NewSnapshotter(td+"snap", snapshotSizeLimit, true,
+		logger, clock, nil, stopCh)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Check the values
+	if snap.LastClock() != 100 {
+		t.Fatalf("bad clock %d", snap.LastClock())
+	}
+	if snap.LastEventClock() != 42 {
+		t.Fatalf("bad clock %d", snap.LastEventClock())
+	}
+	if snap.LastQueryClock() != 50 {
+		t.Fatalf("bad clock %d", snap.LastQueryClock())
+	}
+
+	prev := snap.AliveNodes()
+	if len(prev) == 0 {
+		t.Fatalf("expected alive: %#v", prev)
+	}
+}

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/accessors_test.go

@@ -1,7 +1,7 @@
 package objx
 
 import (
-	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/conversions_test.go

@@ -1,7 +1,7 @@
 package objx
 
 import (
-	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/fixture_test.go

@@ -1,7 +1,7 @@
 package objx
 
 import (
-	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/stretchr/objx/map_test.go

@@ -1,7 +1,7 @@
 package objx
 
 import (
-	"github.com/docker/libnetwork/Godeps/_workspace/src/github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 

Some files were not shown because too many files changed in this diff