diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 5bd5ba08b..2d1b058fc 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -14,39 +14,10 @@ "Comment": "null-5", "Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675" }, - { - "ImportPath": "github.com/alecthomas/kingpin", - "Comment": "v2.1.0-2-gaedd543", - "Rev": "aedd5430ecd39ba1396fee0c00308b494c552b1e" - }, - { - "ImportPath": "github.com/alecthomas/template", - "Rev": "b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0" - }, - { - "ImportPath": "github.com/alecthomas/units", - "Rev": "6b4e7dc5e3143b85ea77909c72caf89416fc2915" - }, - { - "ImportPath": "github.com/anacrolix/jitter", - "Rev": "2ea5c18645100745b24e9f5cfc9b3f6f7eac51ef" - }, - { - "ImportPath": "github.com/anacrolix/missinggo", - "Rev": "4e1ca5963308863b56c31863f60c394a7365ec29" - }, - { - "ImportPath": "github.com/anacrolix/utp", - "Rev": "0bb24de92c268452fb9106ca4fb9302442ca0dee" - }, { "ImportPath": "github.com/beorn7/perks/quantile", "Rev": "b965b613227fddccbfffe13eae360ed3fa822f8d" }, - { - "ImportPath": "github.com/bradfitz/iter", - "Rev": "454541ec3da2a73fc34fd049b19ee5777bf19345" - }, { "ImportPath": "github.com/bren2010/proquint", "Rev": "5958552242606512f714d2e93513b380f43f9991" @@ -75,18 +46,6 @@ "ImportPath": "github.com/codahale/metrics", "Rev": "7c37910bc765e705301b159683480bdd44555c91" }, - { - "ImportPath": "github.com/coreos/go-semver/semver", - "Rev": "568e959cd89871e61434c1143528d9162da89ef2" - }, - { - "ImportPath": "github.com/crowdmob/goamz/aws", - "Rev": "82345796204222aa56be89cf930c316b1297f906" - }, - { - "ImportPath": "github.com/crowdmob/goamz/s3", - "Rev": "82345796204222aa56be89cf930c316b1297f906" - }, { "ImportPath": "github.com/cryptix/mdns", "Rev": "04ff72a32679d57d009c0ac0fc5c4cda10350bad" @@ -107,10 +66,6 @@ "ImportPath": "github.com/facebookgo/atomicfile", "Rev": "6f117f2e7f224fb03eb5e5fba370eade6e2b90c8" }, - { - "ImportPath": "github.com/fd/go-nat", - "Rev": "50e7633d5f27d81490026a13e5b92d2e42d8c6bb" - }, { "ImportPath": "github.com/gogo/protobuf/io", "Rev": "0ac967c269268f1af7d9bcc7927ccc9a589b2b36" @@ -127,22 +82,10 @@ "ImportPath": "github.com/hashicorp/golang-lru", "Rev": "253b2dc1ca8bae42c3b5b6e53dd2eab1a7551116" }, - { - "ImportPath": "github.com/hashicorp/yamux", - "Rev": "9feabe6854fadca1abec9cd3bd2a613fe9a34000" - }, - { - "ImportPath": "github.com/huin/goupnp", - "Rev": "223008361153d7d434c1f0ac990cd3fcae6931f5" - }, { "ImportPath": "github.com/ipfs/go-datastore", "Rev": "e63957b6da369d986ef3e7a3f249779ba3f56c7e" }, - { - "ImportPath": "github.com/jackpal/go-nat-pmp", - "Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1" - }, { "ImportPath": "github.com/jbenet/go-base58", "Rev": "6237cf65f3a6f7111cd8a42be3590df99a66bc7d" @@ -201,34 +144,10 @@ "ImportPath": "github.com/jbenet/go-random-files", "Rev": "737479700b40b4b50e914e963ce8d9d44603e3c8" }, - { - "ImportPath": "github.com/jbenet/go-reuseport", - "Rev": "48959f1fad204b6cf2c0e8d086ef69f03f2de961" - }, - { - "ImportPath": "github.com/jbenet/go-sockaddr/net", - "Rev": "da304f94eea1af8ba8d1faf184623e1f9d9777dc" - }, - { - "ImportPath": "github.com/jbenet/go-stream-muxer", - "Rev": "e2e261765847234749629e0190fef193a4548303" - }, - { - "ImportPath": "github.com/jbenet/go-temp-err-catcher", - "Rev": "aac704a3f4f27190b4ccc05f303a4931fd1241ff" - }, - { - "ImportPath": "github.com/jbenet/goprocess", - "Rev": "64a8220330a485070813201cc05b0c6777f6a516" - }, { "ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil", "Rev": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a" }, - { - "ImportPath": "github.com/miekg/dns", - "Rev": "82ffc45b1f84ff71bd1cebed8b210118ce3d181e" - }, { "ImportPath": "github.com/mitchellh/go-homedir", "Rev": "1f6da4a72e57d4e7edd4a7295a585e0a3999a2d4" @@ -302,14 +221,6 @@ "ImportPath": "github.com/whyrusleeping/go-metrics", "Rev": "1cd8009604ec2238b5a71305a0ecd974066e0e16" }, - { - "ImportPath": "github.com/whyrusleeping/go-multiplex", - "Rev": "474b9aebeb391746f304ddf7c764a5da12319857" - }, - { - "ImportPath": "github.com/whyrusleeping/go-multistream", - "Rev": "31bb014803a6eba2261bda5593e42c016a5f33bb" - }, { "ImportPath": "github.com/whyrusleeping/go-sysinfo", "Rev": "769b7c0b50e8030895abc74ba8107ac715e3162a" diff --git a/Godeps/_workspace/src/github.com/anacrolix/jitter/jitter.go b/Godeps/_workspace/src/github.com/anacrolix/jitter/jitter.go deleted file mode 100644 index 7f0f39b8f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/jitter/jitter.go +++ /dev/null @@ -1,12 +0,0 @@ -package jitter - -import ( - "math/rand" - "time" -) - -func Duration(average, plusMinus time.Duration) (ret time.Duration) { - ret = average - plusMinus - ret += time.Duration(rand.Int63n(2*int64(plusMinus) + 1)) - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr.go deleted file mode 100644 index 7d7a4f8ba..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr.go +++ /dev/null @@ -1,72 +0,0 @@ -package missinggo - -import ( - "net" - "strconv" - "strings" -) - -type HostMaybePort struct { - Host string - Port int - NoPort bool -} - -func (me HostMaybePort) String() string { - if me.NoPort { - return me.Host - } - return net.JoinHostPort(me.Host, strconv.FormatInt(int64(me.Port), 10)) -} - -func SplitHostPort(hostport string) (ret HostMaybePort) { - host, port, err := net.SplitHostPort(hostport) - if err != nil { - if strings.Contains(err.Error(), "missing port") { - ret.Host = hostport - ret.NoPort = true - return - } - panic(err) - } - i64, err := strconv.ParseInt(port, 0, 0) - ret.Host = host - ret.Port = int(i64) - if err != nil { - ret.NoPort = true - } - return -} - -// Extracts the port as an integer from an address string. -func AddrPort(addr net.Addr) int { - switch raw := addr.(type) { - case *net.UDPAddr: - return raw.Port - default: - _, port, err := net.SplitHostPort(addr.String()) - if err != nil { - panic(err) - } - i64, err := strconv.ParseInt(port, 0, 0) - if err != nil { - panic(err) - } - return int(i64) - } -} - -func AddrIP(addr net.Addr) net.IP { - switch raw := addr.(type) { - case *net.UDPAddr: - return raw.IP - case *net.TCPAddr: - return raw.IP - default: - host, _, err := net.SplitHostPort(addr.String()) - if err != nil { - panic(err) - } - return net.ParseIP(host) - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go deleted file mode 100644 index 473d5475e..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package missinggo - -import ( - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" -) - -func TestSplitHostPort(t *testing.T) { - assert.EqualValues(t, HostMaybePort{"a", 1, false}, SplitHostPort("a:1")) - assert.EqualValues(t, HostMaybePort{"a", 0, true}, SplitHostPort("a")) -} - -func TestHostMaybePortString(t *testing.T) { - assert.EqualValues(t, "a:1", (HostMaybePort{"a", 1, false}).String()) - assert.EqualValues(t, "a", (HostMaybePort{"a", 0, true}).String()) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/args/args.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/args/args.go deleted file mode 100644 index 8f0d614f1..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/args/args.go +++ /dev/null @@ -1,15 +0,0 @@ -package args - -import ( - "flag" - "fmt" - "os" -) - -func Parse() { - flag.Parse() - if flag.NArg() != 0 { - fmt.Fprintf(os.Stderr, "unexpected positional arguments\n") - os.Exit(2) - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime.go deleted file mode 100644 index 41ede5895..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime.go +++ /dev/null @@ -1,11 +0,0 @@ -package missinggo - -import ( - "os" - "time" -) - -// Extracts the access time from the FileInfo internals. -func FileInfoAccessTime(fi os.FileInfo) time.Time { - return fileInfoAccessTime(fi) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_darwin.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_darwin.go deleted file mode 100644 index 5ccbc434f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_darwin.go +++ /dev/null @@ -1,12 +0,0 @@ -package missinggo - -import ( - "os" - "syscall" - "time" -) - -func fileInfoAccessTime(fi os.FileInfo) time.Time { - ts := fi.Sys().(*syscall.Stat_t).Atimespec - return time.Unix(int64(ts.Sec), int64(ts.Nsec)) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_freebsd.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_freebsd.go deleted file mode 100644 index 5ccbc434f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_freebsd.go +++ /dev/null @@ -1,12 +0,0 @@ -package missinggo - -import ( - "os" - "syscall" - "time" -) - -func fileInfoAccessTime(fi os.FileInfo) time.Time { - ts := fi.Sys().(*syscall.Stat_t).Atimespec - return time.Unix(int64(ts.Sec), int64(ts.Nsec)) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_linux.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_linux.go deleted file mode 100644 index e599d8b77..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_linux.go +++ /dev/null @@ -1,12 +0,0 @@ -package missinggo - -import ( - "os" - "syscall" - "time" -) - -func fileInfoAccessTime(fi os.FileInfo) time.Time { - ts := fi.Sys().(*syscall.Stat_t).Atim - return time.Unix(int64(ts.Sec), int64(ts.Nsec)) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_windows.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_windows.go deleted file mode 100644 index bedf8c3f2..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/atime_windows.go +++ /dev/null @@ -1,12 +0,0 @@ -package missinggo - -import ( - "os" - "syscall" - "time" -) - -func fileInfoAccessTime(fi os.FileInfo) time.Time { - ts := fi.Sys().(syscall.Win32FileAttributeData).LastAccessTime - return time.Unix(0, int64(ts.Nanoseconds())) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/castslice.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/castslice.go deleted file mode 100644 index 7be8823a1..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/castslice.go +++ /dev/null @@ -1,17 +0,0 @@ -package missinggo - -import ( - "reflect" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" -) - -func ConvertToSliceOfEmptyInterface(slice interface{}) (ret []interface{}) { - v := reflect.ValueOf(slice) - l := v.Len() - ret = make([]interface{}, 0, l) - for i := range iter.N(v.Len()) { - ret = append(ret, v.Index(i).Interface()) - } - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/go-env/main.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/go-env/main.go deleted file mode 100644 index 66a736e00..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/go-env/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "fmt" - "os" -) - -func main() { - for _, v := range os.Environ() { - fmt.Printf("%s\n", v) - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/nop/main.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/nop/main.go deleted file mode 100644 index 38dd16da6..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/nop/main.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -func main() {} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-escape/main.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-escape/main.go deleted file mode 100644 index cddd9d93d..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-escape/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "os" -) - -func main() { - fmt.Println(url.QueryEscape(os.Args[1])) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-unescape/main.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-unescape/main.go deleted file mode 100644 index 3099cc8df..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/cmd/query-unescape/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "os" -) - -func main() { - fmt.Println(url.QueryUnescape(os.Args[1])) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy.go deleted file mode 100644 index 79aa58ff7..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy.go +++ /dev/null @@ -1,32 +0,0 @@ -package missinggo - -import ( - "fmt" - "reflect" -) - -func CopyExact(dest interface{}, src interface{}) { - dV := reflect.ValueOf(dest) - sV := reflect.ValueOf(src) - if dV.Kind() == reflect.Ptr { - dV = dV.Elem() - } - if dV.Kind() == reflect.Array && !dV.CanAddr() { - panic(fmt.Sprintf("dest not addressable: %T", dest)) - } - if sV.Kind() == reflect.Ptr { - sV = sV.Elem() - } - if sV.Kind() == reflect.String { - sV = sV.Convert(reflect.SliceOf(dV.Type().Elem())) - } - if !sV.IsValid() { - panic("invalid source, probably nil") - } - if dV.Len() != sV.Len() { - panic(fmt.Sprintf("dest len (%d) != src len (%d)", dV.Len(), sV.Len())) - } - if dV.Len() != reflect.Copy(dV, sV) { - panic("dammit") - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy_test.go deleted file mode 100644 index 190f2a10f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/copy_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package missinggo - -import ( - "bytes" - "strings" - "testing" -) - -func TestCopyToArray(t *testing.T) { - var arr [3]byte - bb := []byte{1, 2, 3} - CopyExact(&arr, bb) - if !bytes.Equal(arr[:], bb) { - t.FailNow() - } -} - -func TestCopyToSlicedArray(t *testing.T) { - var arr [5]byte - CopyExact(arr[:], "hello") - if !bytes.Equal(arr[:], []byte("hello")) { - t.FailNow() - } -} - -func TestCopyDestNotAddr(t *testing.T) { - defer func() { - r := recover() - if r == nil { - t.FailNow() - } - t.Log(r) - }() - var arr [3]byte - CopyExact(arr, "nope") -} - -func TestCopyLenMismatch(t *testing.T) { - defer func() { - r := recover() - if r == nil { - t.FailNow() - } - t.Log(r) - }() - CopyExact(make([]byte, 2), "abc") -} - -func TestCopySrcString(t *testing.T) { - dest := make([]byte, 3) - CopyExact(dest, "lol") - if string(dest) != "lol" { - t.FailNow() - } - func() { - defer func() { - r := recover() - if r == nil { - t.FailNow() - } - }() - CopyExact(dest, "rofl") - }() - var arr [5]byte - CopyExact(&arr, interface{}("hello")) - if string(arr[:]) != "hello" { - t.FailNow() - } -} - -func TestCopySrcNilInterface(t *testing.T) { - var arr [3]byte - defer func() { - r := recover().(string) - if !strings.Contains(r, "invalid source") { - t.FailNow() - } - }() - CopyExact(&arr, nil) -} - -func TestCopySrcPtr(t *testing.T) { - var bigDst [1024]byte - var bigSrc [1024]byte = [1024]byte{'h', 'i'} - CopyExact(&bigDst, &bigSrc) - if !bytes.Equal(bigDst[:], bigSrc[:]) { - t.FailNow() - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/croak.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/croak.go deleted file mode 100644 index ded86ef0b..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/croak.go +++ /dev/null @@ -1,18 +0,0 @@ -package missinggo - -import ( - "fmt" - "os" -) - -func Unchomp(s string) string { - if len(s) > 0 && s[len(s)-1] == '\n' { - return s - } - return s + "\n" -} - -func Fatal(msg interface{}) { - os.Stderr.WriteString(Unchomp(fmt.Sprint(msg))) - os.Exit(1) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/doc.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/doc.go deleted file mode 100644 index 9b8aa8ddd..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package missinggo contains miscellaneous helpers used in many of anacrolix' -// projects. -package missinggo diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/expvarIndentMap.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/expvarIndentMap.go deleted file mode 100644 index c99529956..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/expvarIndentMap.go +++ /dev/null @@ -1,35 +0,0 @@ -package missinggo - -import ( - "bytes" - "expvar" - "fmt" -) - -type IndentMap struct { - expvar.Map -} - -var _ expvar.Var = &IndentMap{} - -func NewExpvarIndentMap(name string) *IndentMap { - v := new(IndentMap) - v.Init() - expvar.Publish(name, v) - return v -} - -func (v *IndentMap) String() string { - var b bytes.Buffer - fmt.Fprintf(&b, "{") - first := true - v.Do(func(kv expvar.KeyValue) { - if !first { - fmt.Fprintf(&b, ",") - } - fmt.Fprintf(&b, "\n\t%q: %v", kv.Key, kv.Value) - first = false - }) - fmt.Fprintf(&b, "}") - return b.String() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache.go deleted file mode 100644 index 734169c69..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache.go +++ /dev/null @@ -1,269 +0,0 @@ -package filecache - -import ( - "errors" - "log" - "os" - "path" - "path/filepath" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -type Cache struct { - mu sync.Mutex - capacity int64 - filled int64 - items *lruItems - paths map[string]ItemInfo - root string -} - -type CacheInfo struct { - Capacity int64 - Filled int64 - NumItems int -} - -type ItemInfo struct { - Accessed time.Time - Size int64 - Path string -} - -// Calls the function for every item known to the cache. The ItemInfo should -// not be modified. -func (me *Cache) WalkItems(cb func(ItemInfo)) { - me.mu.Lock() - defer me.mu.Unlock() - for e := me.items.Front(); e != nil; e = e.Next() { - cb(e.Value().(ItemInfo)) - } -} - -func (me *Cache) Info() (ret CacheInfo) { - me.mu.Lock() - defer me.mu.Unlock() - ret.Capacity = me.capacity - ret.Filled = me.filled - ret.NumItems = len(me.paths) - return -} - -func (me *Cache) SetCapacity(capacity int64) { - me.mu.Lock() - defer me.mu.Unlock() - me.capacity = capacity -} - -func NewCache(root string) (ret *Cache, err error) { - if !filepath.IsAbs(root) { - err = errors.New("root is not an absolute filepath") - return - } - ret = &Cache{ - root: root, - capacity: -1, // unlimited - } - ret.mu.Lock() - go func() { - defer ret.mu.Unlock() - ret.rescan() - }() - return -} - -// An empty return path is an error. -func sanitizePath(p string) (ret string) { - if p == "" { - return - } - ret = path.Clean("/" + p) - if ret[0] == '/' { - ret = ret[1:] - } - return -} - -// Leaf is a descendent of root. -func pruneEmptyDirs(root string, leaf string) (err error) { - rootInfo, err := os.Stat(root) - if err != nil { - return - } - for { - var leafInfo os.FileInfo - leafInfo, err = os.Stat(leaf) - if os.IsNotExist(err) { - goto parent - } - if err != nil { - return - } - if !leafInfo.IsDir() { - return - } - if os.SameFile(rootInfo, leafInfo) { - return - } - if os.Remove(leaf) != nil { - return - } - parent: - leaf = filepath.Dir(leaf) - } -} - -func (me *Cache) Remove(path string) (err error) { - path = sanitizePath(path) - me.mu.Lock() - defer me.mu.Unlock() - err = me.remove(path) - return -} - -var ( - ErrBadPath = errors.New("bad path") - ErrIsDir = errors.New("is directory") -) - -func (me *Cache) OpenFile(path string, flag int) (ret *File, err error) { - path = sanitizePath(path) - if path == "" { - err = ErrIsDir - return - } - f, err := os.OpenFile(me.realpath(path), flag, 0644) - if flag&os.O_CREATE != 0 && os.IsNotExist(err) { - os.MkdirAll(me.root, 0755) - os.MkdirAll(filepath.Dir(me.realpath(path)), 0755) - f, err = os.OpenFile(me.realpath(path), flag, 0644) - if err != nil { - me.pruneEmptyDirs(path) - } - } - if err != nil { - return - } - ret = &File{ - c: me, - path: path, - f: f, - } - me.mu.Lock() - go func() { - defer me.mu.Unlock() - me.statItem(path, time.Now()) - }() - return -} - -func (me *Cache) rescan() { - me.filled = 0 - me.items = newLRUItems() - me.paths = make(map[string]ItemInfo) - err := filepath.Walk(me.root, func(path string, info os.FileInfo, err error) error { - if os.IsNotExist(err) { - return nil - } - if err != nil { - return err - } - if info.IsDir() { - return nil - } - path, err = filepath.Rel(me.root, path) - if err != nil { - log.Print(err) - return nil - } - me.statItem(path, time.Time{}) - return nil - }) - if err != nil { - panic(err) - } -} - -func (me *Cache) insertItem(i ItemInfo) { - me.items.Insert(i) -} - -func (me *Cache) removeInfo(path string) (ret ItemInfo, ok bool) { - ret, ok = me.paths[path] - if !ok { - return - } - if !me.items.Remove(ret) { - panic(ret) - } - me.filled -= ret.Size - delete(me.paths, path) - return -} - -// Triggers the item for path to be updated. If access is non-zero, set the -// item's access time to that value, otherwise deduce it appropriately. -func (me *Cache) statItem(path string, access time.Time) { - info, ok := me.removeInfo(path) - fi, err := os.Stat(me.realpath(path)) - if os.IsNotExist(err) { - return - } - if err != nil { - panic(err) - } - if !ok { - info.Path = path - } - if !access.IsZero() { - info.Accessed = access - } - if info.Accessed.IsZero() { - info.Accessed = missinggo.FileInfoAccessTime(fi) - } - info.Size = fi.Size() - me.filled += info.Size - me.insertItem(info) - me.paths[path] = info -} - -func (me *Cache) realpath(path string) string { - return filepath.Join(me.root, filepath.FromSlash(path)) -} - -func (me *Cache) TrimToCapacity() { - me.mu.Lock() - defer me.mu.Unlock() - me.trimToCapacity() -} - -func (me *Cache) pruneEmptyDirs(path string) { - pruneEmptyDirs(me.root, me.realpath(path)) -} - -func (me *Cache) remove(path string) (err error) { - err = os.Remove(me.realpath(path)) - if os.IsNotExist(err) { - err = nil - } - me.pruneEmptyDirs(path) - me.removeInfo(path) - return -} - -func (me *Cache) trimToCapacity() { - if me.capacity < 0 { - return - } - for me.filled > me.capacity { - item := me.items.LRU() - me.remove(item.Path) - } -} - -func (me *Cache) pathInfo(p string) ItemInfo { - return me.paths[p] -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go deleted file mode 100644 index 9587fedfb..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package filecache - -import ( - "io" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -func TestCache(t *testing.T) { - td, err := ioutil.TempDir("", "gotest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(td) - c, err := NewCache(filepath.Join(td, "cache")) - if err != nil { - t.Fatal(err) - } - assert.EqualValues(t, 0, c.Info().Filled) - c.WalkItems(func(i ItemInfo) {}) - _, err = c.OpenFile("/", os.O_CREATE) - assert.NotNil(t, err) - _, err = c.OpenFile("", os.O_CREATE) - assert.NotNil(t, err) - c.WalkItems(func(i ItemInfo) {}) - require.Equal(t, 0, c.Info().NumItems) - _, err = c.OpenFile("notexist", 0) - assert.True(t, os.IsNotExist(err), err) - _, err = c.OpenFile("/notexist", 0) - assert.True(t, os.IsNotExist(err), err) - _, err = c.OpenFile("/dir/notexist", 0) - assert.True(t, os.IsNotExist(err), err) - f, err := c.OpenFile("dir/blah", os.O_CREATE) - require.NoError(t, err) - defer f.Close() - c.WalkItems(func(i ItemInfo) {}) - assert.True(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("cache/dir/blah")))) - assert.True(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("cache/dir/")))) - assert.Equal(t, 1, c.Info().NumItems) - f.Remove() - assert.False(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("dir/blah")))) - assert.False(t, missinggo.FilePathExists(filepath.Join(td, filepath.FromSlash("dir/")))) - _, err = f.Read(nil) - assert.NotEqual(t, io.EOF, err) - a, err := c.OpenFile("/a", os.O_CREATE|os.O_WRONLY) - defer a.Close() - require.Nil(t, err) - b, err := c.OpenFile("b", os.O_CREATE|os.O_WRONLY) - defer b.Close() - require.Nil(t, err) - c.mu.Lock() - assert.True(t, c.pathInfo("a").Accessed.Before(c.pathInfo("b").Accessed)) - c.mu.Unlock() - n, err := a.Write([]byte("hello")) - assert.Nil(t, err) - assert.EqualValues(t, 5, n) - assert.EqualValues(t, 5, c.Info().Filled) - assert.True(t, c.pathInfo("b").Accessed.Before(c.pathInfo("a").Accessed)) - c.SetCapacity(5) - n, err = a.Write([]byte(" world")) - assert.NotNil(t, err) - _, err = b.Write([]byte("boom!")) - // "a" and "b" have been evicted. - assert.NotNil(t, err) - assert.EqualValues(t, 0, c.Info().Filled) - assert.EqualValues(t, 0, c.Info().NumItems) - _, err = a.Seek(0, os.SEEK_SET) - assert.NotNil(t, err) -} - -func TestSanitizePath(t *testing.T) { - assert.Equal(t, "", sanitizePath("////")) - assert.Equal(t, "", sanitizePath("/../..")) - assert.Equal(t, "a", sanitizePath("/a//b/..")) - assert.Equal(t, "a", sanitizePath("../a")) - assert.Equal(t, "a", sanitizePath("./a")) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/file.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/file.go deleted file mode 100644 index 70e4743a1..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/file.go +++ /dev/null @@ -1,117 +0,0 @@ -package filecache - -import ( - "errors" - "math" - "os" - "sync" - "time" -) - -type File struct { - mu sync.Mutex - c *Cache - path string - f *os.File - gone bool -} - -func (me *File) Remove() (err error) { - return me.c.Remove(me.path) -} - -func (me *File) Seek(offset int64, whence int) (ret int64, err error) { - ret, err = me.f.Seek(offset, whence) - return -} - -func (me *File) maxWrite() (max int64, err error) { - if me.c.capacity < 0 { - max = math.MaxInt64 - return - } - pos, err := me.Seek(0, os.SEEK_CUR) - if err != nil { - return - } - max = me.c.capacity - pos - if max < 0 { - max = 0 - } - return -} - -var ( - ErrFileTooLarge = errors.New("file too large for cache") - ErrFileDisappeared = errors.New("file disappeared") -) - -func (me *File) checkGone() { - if me.gone { - return - } - ffi, _ := me.Stat() - fsfi, _ := os.Stat(me.c.realpath(me.path)) - me.gone = !os.SameFile(ffi, fsfi) -} - -func (me *File) goneErr() error { - me.mu.Lock() - defer me.mu.Unlock() - me.checkGone() - if me.gone { - me.f.Close() - return ErrFileDisappeared - } - return nil -} - -func (me *File) Write(b []byte) (n int, err error) { - err = me.goneErr() - if err != nil { - return - } - n, err = me.f.Write(b) - me.c.mu.Lock() - me.c.statItem(me.path, time.Now()) - me.c.trimToCapacity() - me.c.mu.Unlock() - if err == nil { - err = me.goneErr() - } - return -} - -func (me *File) Close() error { - return me.f.Close() -} - -func (me *File) Stat() (os.FileInfo, error) { - return me.f.Stat() -} - -func (me *File) Read(b []byte) (n int, err error) { - err = me.goneErr() - if err != nil { - return - } - defer func() { - me.c.mu.Lock() - defer me.c.mu.Unlock() - me.c.statItem(me.path, time.Now()) - }() - return me.f.Read(b) -} - -func (me *File) ReadAt(b []byte, off int64) (n int, err error) { - err = me.goneErr() - if err != nil { - return - } - defer func() { - me.c.mu.Lock() - defer me.c.mu.Unlock() - me.c.statItem(me.path, time.Now()) - }() - return me.f.ReadAt(b, off) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go deleted file mode 100644 index bd4d2bf92..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go +++ /dev/null @@ -1,94 +0,0 @@ -package filecache - -import ( - "container/list" - "io" - - "gx/ipfs/QmVgtwPh2NNoZTSyYkr4Y3epaYACBKf26r8hV6EFA7xS6c/b" -) - -type Iterator interface { - Next() Iterator - Value() interface{} -} - -type listElementIterator struct { - le *list.Element -} - -func (me listElementIterator) Next() Iterator { - e := me.le.Next() - if e == nil { - return nil - } - return listElementIterator{e} -} - -func (me listElementIterator) Value() interface{} { - return me.le.Value -} - -func newLRUItems() *lruItems { - return &lruItems{b.TreeNew(func(_a, _b interface{}) int { - a := _a.(ItemInfo) - b := _b.(ItemInfo) - if a.Accessed != b.Accessed { - if a.Accessed.Before(b.Accessed) { - return -1 - } else { - return 1 - } - } - if a.Path == b.Path { - return 0 - } - if a.Path < b.Path { - return -1 - } - return 1 - })} -} - -type lruItems struct { - tree *b.Tree -} - -type bEnumeratorIterator struct { - e *b.Enumerator - v ItemInfo -} - -func (me bEnumeratorIterator) Next() Iterator { - _, v, err := me.e.Next() - if err == io.EOF { - return nil - } - return bEnumeratorIterator{me.e, v.(ItemInfo)} -} - -func (me bEnumeratorIterator) Value() interface{} { - return me.v -} - -func (me *lruItems) Front() Iterator { - e, _ := me.tree.SeekFirst() - if e == nil { - return nil - } - return bEnumeratorIterator{ - e: e, - }.Next() -} - -func (me *lruItems) LRU() ItemInfo { - _, v := me.tree.First() - return v.(ItemInfo) -} - -func (me *lruItems) Insert(ii ItemInfo) { - me.tree.Set(ii, ii) -} - -func (me *lruItems) Remove(ii ItemInfo) bool { - return me.tree.Delete(ii) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems_test.go deleted file mode 100644 index abe70a8bd..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package filecache - -import ( - "math/rand" - "testing" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" -) - -func BenchmarkInsert(b *testing.B) { - for range iter.N(b.N) { - li := newLRUItems() - for range iter.N(10000) { - r := rand.Int63() - t := time.Unix(r/1e9, r%1e9) - li.Insert(ItemInfo{ - Accessed: t, - }) - } - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange.go deleted file mode 100644 index acf10023e..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange.go +++ /dev/null @@ -1,38 +0,0 @@ -package missinggo - -import ( - "regexp" - "strconv" -) - -type HTTPBytesContentRange struct { - First, Last, Length int64 -} - -var bytesContentRangeRegexp = regexp.MustCompile(`bytes[ =](\d+)-(\d+)/(\d+|\*)`) - -func ParseHTTPBytesContentRange(s string) (ret HTTPBytesContentRange, ok bool) { - ss := bytesContentRangeRegexp.FindStringSubmatch(s) - if ss == nil { - return - } - var err error - ret.First, err = strconv.ParseInt(ss[1], 10, 64) - if err != nil { - return - } - ret.Last, err = strconv.ParseInt(ss[2], 10, 64) - if err != nil { - return - } - if ss[3] == "*" { - ret.Length = -1 - } else { - ret.Length, err = strconv.ParseInt(ss[3], 10, 64) - if err != nil { - return - } - } - ok = true - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go deleted file mode 100644 index 30505f1a7..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package missinggo - -import ( - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" -) - -func TestParseHTTPContentRange(t *testing.T) { - for _, _case := range []struct { - h string - cr *HTTPBytesContentRange - }{ - {"", nil}, - {"1-2/*", nil}, - {"bytes=1-2/3", &HTTPBytesContentRange{1, 2, 3}}, - {"bytes=12-34/*", &HTTPBytesContentRange{12, 34, -1}}, - {" bytes=12-34/*", &HTTPBytesContentRange{12, 34, -1}}, - {" bytes 12-34/56", &HTTPBytesContentRange{12, 34, 56}}, - } { - ret, ok := ParseHTTPBytesContentRange(_case.h) - assert.Equal(t, _case.cr != nil, ok) - if _case.cr != nil { - assert.Equal(t, *_case.cr, ret) - } - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpfile/httpfile.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpfile/httpfile.go deleted file mode 100644 index b534c825e..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpfile/httpfile.go +++ /dev/null @@ -1,222 +0,0 @@ -package httpfile - -import ( - "bytes" - "errors" - "fmt" - "io" - "net/http" - "os" - "strconv" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -type File struct { - off int64 - r io.ReadCloser - rOff int64 - length int64 - url string -} - -func OpenSectionReader(url string, off, n int64) (ret io.ReadCloser, err error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return - } - req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+n-1)) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return - } - if resp.StatusCode == http.StatusNotFound { - err = ErrNotFound - resp.Body.Close() - return - } - if resp.StatusCode != http.StatusPartialContent { - err = fmt.Errorf("bad response status: %s", resp.Status) - resp.Body.Close() - return - } - ret = resp.Body - return -} - -func Open(url string) *File { - return &File{ - url: url, - } -} - -func (me *File) prepareReader() (err error) { - if me.r != nil && me.off != me.rOff { - me.r.Close() - me.r = nil - } - if me.r != nil { - return nil - } - req, err := http.NewRequest("GET", me.url, nil) - if err != nil { - return - } - if me.off != 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", me.off)) - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return - } - switch resp.StatusCode { - case http.StatusPartialContent: - cr, ok := missinggo.ParseHTTPBytesContentRange(resp.Header.Get("Content-Range")) - if !ok || cr.First != me.off { - err = errors.New("bad response") - resp.Body.Close() - return - } - me.length = cr.Length - case http.StatusOK: - if me.off != 0 { - err = errors.New("bad response") - resp.Body.Close() - return - } - if h := resp.Header.Get("Content-Length"); h != "" { - var cl uint64 - cl, err = strconv.ParseUint(h, 10, 64) - if err != nil { - resp.Body.Close() - return - } - me.length = int64(cl) - } - default: - err = errors.New(resp.Status) - resp.Body.Close() - return - } - me.r = resp.Body - me.rOff = me.off - return -} - -func (me *File) Read(b []byte) (n int, err error) { - err = me.prepareReader() - if err != nil { - return - } - n, err = me.r.Read(b) - me.off += int64(n) - me.rOff += int64(n) - return -} - -func instanceLength(r *http.Response) (int64, error) { - switch r.StatusCode { - case http.StatusOK: - if h := r.Header.Get("Content-Length"); h != "" { - return strconv.ParseInt(h, 10, 64) - } else { - return -1, nil - } - case http.StatusPartialContent: - cr, ok := missinggo.ParseHTTPBytesContentRange(r.Header.Get("Content-Range")) - if !ok { - return -1, errors.New("bad 206 response") - } - return cr.Length, nil - default: - return -1, errors.New(r.Status) - } -} - -func (me *File) Seek(offset int64, whence int) (ret int64, err error) { - switch whence { - case os.SEEK_SET: - ret = offset - case os.SEEK_CUR: - ret = me.off + offset - case os.SEEK_END: - if me.length < 0 { - err = errors.New("length unknown") - return - } - ret = me.length + offset - default: - err = fmt.Errorf("unhandled whence: %d", whence) - return - } - me.off = ret - return -} - -func (me *File) Write(b []byte) (n int, err error) { - req, err := http.NewRequest("PATCH", me.url, bytes.NewReader(b)) - if err != nil { - return - } - req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-", me.off)) - req.ContentLength = int64(len(b)) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return - } - resp.Body.Close() - if resp.StatusCode != http.StatusPartialContent { - err = errors.New(resp.Status) - return - } - n = len(b) - me.off += int64(n) - return -} - -var ( - ErrNotFound = errors.New("not found") -) - -// Returns the length of the resource in bytes. -func GetLength(url string) (ret int64, err error) { - resp, err := http.Head(url) - if err != nil { - return - } - resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - err = ErrNotFound - return - } - return instanceLength(resp) -} - -func (me *File) Close() error { - me.url = "" - if me.r != nil { - me.r.Close() - me.r = nil - } - return nil -} - -func Delete(urlStr string) (err error) { - req, err := http.NewRequest("DELETE", urlStr, nil) - if err != nil { - return - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return - } - resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - err = ErrNotFound - return - } - if resp.StatusCode != 200 { - err = fmt.Errorf("response: %s", resp.Status) - } - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpgzip.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpgzip.go deleted file mode 100644 index 503eb0f79..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpgzip.go +++ /dev/null @@ -1,47 +0,0 @@ -package missinggo - -import ( - "compress/gzip" - "io" - "net/http" - "strings" -) - -type gzipResponseWriter struct { - io.Writer - http.ResponseWriter - haveWritten bool -} - -func (w *gzipResponseWriter) Write(b []byte) (int, error) { - if w.haveWritten { - goto write - } - w.haveWritten = true - if w.Header().Get("Content-Type") != "" { - goto write - } - if type_ := http.DetectContentType(b); type_ != "application/octet-stream" { - w.Header().Set("Content-Type", type_) - } -write: - return w.Writer.Write(b) -} - -// Gzips response body if the request says it'll allow it. -func GzipHTTPHandler(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || w.Header().Get("Content-Encoding") != "" || w.Header().Get("Vary") != "" { - h.ServeHTTP(w, r) - return - } - w.Header().Set("Content-Encoding", "gzip") - w.Header().Set("Vary", "Accept-Encoding") - gz := gzip.NewWriter(w) - defer gz.Close() - h.ServeHTTP(&gzipResponseWriter{ - Writer: gz, - ResponseWriter: w, - }, r) - }) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpresponsestatus.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpresponsestatus.go deleted file mode 100644 index a42e09801..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpresponsestatus.go +++ /dev/null @@ -1,60 +0,0 @@ -package missinggo - -import ( - "bufio" - "io" - "net" - "net/http" -) - -// A http.ResponseWriter that tracks the status of the response. The status -// code, and number of bytes written for example. -type StatusResponseWriter struct { - RW http.ResponseWriter - Code int - BytesWritten int64 -} - -var _ http.ResponseWriter = &StatusResponseWriter{} - -func (me *StatusResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - return me.RW.(http.Hijacker).Hijack() -} - -func (me *StatusResponseWriter) CloseNotify() <-chan bool { - return me.RW.(http.CloseNotifier).CloseNotify() -} - -func (me *StatusResponseWriter) Flush() { - me.RW.(http.Flusher).Flush() -} - -func (me *StatusResponseWriter) Header() http.Header { - return me.RW.Header() -} - -func (me *StatusResponseWriter) Write(b []byte) (n int, err error) { - if me.Code == 0 { - me.Code = 200 - } - n, err = me.RW.Write(b) - me.BytesWritten += int64(n) - return -} - -func (me *StatusResponseWriter) WriteHeader(code int) { - me.RW.WriteHeader(code) - me.Code = code -} - -type ReaderFromStatusResponseWriter struct { - StatusResponseWriter - io.ReaderFrom -} - -func NewReaderFromStatusResponseWriter(w http.ResponseWriter) *ReaderFromStatusResponseWriter { - return &ReaderFromStatusResponseWriter{ - StatusResponseWriter{RW: w}, - w.(io.ReaderFrom), - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby.go deleted file mode 100644 index 17761facc..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby.go +++ /dev/null @@ -1,81 +0,0 @@ -package itertools - -type groupBy struct { - curKey interface{} - curKeyOk bool - curValue interface{} - keyFunc func(interface{}) interface{} - input Iterator - groupKey interface{} - groupKeyOk bool -} - -type Group interface { - Iterator - Key() interface{} -} - -type group struct { - gb *groupBy - key interface{} - first bool -} - -func (me *group) Next() (ok bool) { - if me.first { - me.first = false - return true - } - me.gb.advance() - if !me.gb.curKeyOk || me.gb.curKey != me.key { - return - } - ok = true - return -} - -func (me group) Value() (ret interface{}) { - ret = me.gb.curValue - return -} - -func (me group) Key() interface{} { - return me.key -} - -func (me *groupBy) advance() { - me.curKeyOk = me.input.Next() - if me.curKeyOk { - me.curValue = me.input.Value() - me.curKey = me.keyFunc(me.curValue) - } -} - -func (me *groupBy) Next() (ok bool) { - for me.curKey == me.groupKey { - ok = me.input.Next() - if !ok { - return - } - me.curValue = me.input.Value() - me.curKey = me.keyFunc(me.curValue) - me.curKeyOk = true - } - me.groupKey = me.curKey - me.groupKeyOk = true - return true -} - -func (me *groupBy) Value() (ret interface{}) { - return &group{me, me.groupKey, true} -} - -func GroupBy(input Iterator, keyFunc func(interface{}) interface{}) Iterator { - if keyFunc == nil { - keyFunc = func(a interface{}) interface{} { return a } - } - return &groupBy{ - input: input, - keyFunc: keyFunc, - } -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go deleted file mode 100644 index 26143e14b..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package itertools - -import ( - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" -) - -func TestGroupByKey(t *testing.T) { - var ks []byte - gb := GroupBy(StringIterator("AAAABBBCCDAABBB"), nil) - for gb.Next() { - ks = append(ks, gb.Value().(Group).Key().(byte)) - } - t.Log(ks) - require.EqualValues(t, "ABCDAB", ks) -} - -func TestGroupByList(t *testing.T) { - var gs []string - gb := GroupBy(StringIterator("AAAABBBCCD"), nil) - for gb.Next() { - i := gb.Value().(Iterator) - var g string - for i.Next() { - g += string(i.Value().(byte)) - } - gs = append(gs, g) - } - t.Log(gs) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator.go deleted file mode 100644 index ad8737343..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator.go +++ /dev/null @@ -1,41 +0,0 @@ -package itertools - -import "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" - -type Iterator interface { - Next() bool - Value() interface{} -} - -type sliceIterator struct { - slice []interface{} - value interface{} - ok bool -} - -func (me *sliceIterator) Next() bool { - if len(me.slice) == 0 { - return false - } - me.value = me.slice[0] - me.slice = me.slice[1:] - me.ok = true - return true -} - -func (me *sliceIterator) Value() interface{} { - if !me.ok { - panic("no value; call Next") - } - return me.value -} - -func SliceIterator(a []interface{}) Iterator { - return &sliceIterator{ - slice: a, - } -} - -func StringIterator(a string) Iterator { - return SliceIterator(missinggo.ConvertToSliceOfEmptyInterface(a)) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go deleted file mode 100644 index 8a1bc102d..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package itertools - -import ( - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" -) - -func TestIterator(t *testing.T) { - const s = "AAAABBBCCDAABBB" - si := StringIterator(s) - for i := range s { - require.True(t, si.Next()) - require.Equal(t, s[i], si.Value().(byte)) - } - require.False(t, si.Next()) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/net.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/net.go deleted file mode 100644 index ce406d3b8..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/net.go +++ /dev/null @@ -1,26 +0,0 @@ -package missinggo - -import ( - "net" -) - -type HostPort struct { - Host string // Just the host, with no port. - Port string // May be empty if no port was given. - Err error // The error returned from net.SplitHostPort. -} - -// Parse a "hostport" string, a concept that floats around the stdlib a lot -// and is painful to work with. If no port is present, what's usually present -// is just the host. -func ParseHostPort(hostPort string) (ret HostPort) { - ret.Host, ret.Port, ret.Err = net.SplitHostPort(hostPort) - if ret.Err != nil { - ret.Host = hostPort - } - return -} - -func (me *HostPort) Join() string { - return net.JoinHostPort(me.Host, me.Port) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/path.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/path.go deleted file mode 100644 index 6e3428cb6..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/path.go +++ /dev/null @@ -1,20 +0,0 @@ -package missinggo - -import ( - "os" - "path" -) - -// Splits the pathname p into Root and Ext, such that Root+Ext==p. -func PathSplitExt(p string) (ret struct { - Root, Ext string -}) { - ret.Ext = path.Ext(p) - ret.Root = p[:len(p)-len(ret.Ext)] - return -} - -func FilePathExists(p string) bool { - _, err := os.Stat(p) - return err == nil -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/path_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/path_test.go deleted file mode 100644 index a38aa2e3e..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/path_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package missinggo - -import ( - "fmt" -) - -func ExamplePathSplitExt() { - fmt.Printf("%q\n", PathSplitExt(".cshrc")) - fmt.Printf("%q\n", PathSplitExt("dir/a.ext")) - fmt.Printf("%q\n", PathSplitExt("dir/.rc")) - fmt.Printf("%q\n", PathSplitExt("home/.secret/file")) - // Output: - // {"" ".cshrc"} - // {"dir/a" ".ext"} - // {"dir/" ".rc"} - // {"home/.secret/file" ""} -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/mutex.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/mutex.go deleted file mode 100644 index 095e9990d..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/mutex.go +++ /dev/null @@ -1,48 +0,0 @@ -package perf - -import ( - "sync" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -type TimedLocker struct { - L sync.Locker - Desc string -} - -func (me *TimedLocker) Lock() { - tr := NewTimer() - me.L.Lock() - tr.Stop(me.Desc) -} - -func (me *TimedLocker) Unlock() { - me.L.Unlock() -} - -type TimedRWLocker struct { - RWL missinggo.RWLocker - WriteDesc string - ReadDesc string -} - -func (me *TimedRWLocker) Lock() { - tr := NewTimer() - me.RWL.Lock() - tr.Stop(me.WriteDesc) -} - -func (me *TimedRWLocker) Unlock() { - me.RWL.Unlock() -} - -func (me *TimedRWLocker) RLock() { - tr := NewTimer() - me.RWL.RLock() - tr.Stop(me.ReadDesc) -} - -func (me *TimedRWLocker) RUnlock() { - me.RWL.RUnlock() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf.go deleted file mode 100644 index 4caf9fb60..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf.go +++ /dev/null @@ -1,92 +0,0 @@ -package perf - -import ( - "bytes" - "expvar" - "fmt" - "strconv" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -var ( - em = missinggo.NewExpvarIndentMap("perfBuckets") - mu sync.RWMutex -) - -type Timer struct { - started time.Time -} - -func NewTimer() Timer { - return Timer{time.Now()} -} - -func bucketExponent(d time.Duration) int { - e := -9 - for d != 0 { - d /= 10 - e++ - } - return e -} - -type buckets struct { - mu sync.Mutex - buckets []int64 -} - -func (me *buckets) Add(t time.Duration) { - e := bucketExponent(t) - me.mu.Lock() - for e+9 >= len(me.buckets) { - me.buckets = append(me.buckets, 0) - } - me.buckets[e+9]++ - me.mu.Unlock() -} - -func (me *buckets) String() string { - var b bytes.Buffer - fmt.Fprintf(&b, "{") - first := true - me.mu.Lock() - for i, count := range me.buckets { - if first { - if count == 0 { - continue - } - first = false - } else { - fmt.Fprintf(&b, ", ") - } - key := strconv.Itoa(i - 9) - fmt.Fprintf(&b, "%q: %d", key, count) - } - me.mu.Unlock() - fmt.Fprintf(&b, "}") - return b.String() -} - -var _ expvar.Var = &buckets{} - -func (t *Timer) Stop(desc string) time.Duration { - d := time.Since(t.started) - mu.RLock() - _m := em.Get(desc) - mu.RUnlock() - if _m == nil { - mu.Lock() - _m = em.Get(desc) - if _m == nil { - _m = new(buckets) - em.Set(desc, _m) - } - mu.Unlock() - } - m := _m.(*buckets) - m.Add(d) - return d -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go deleted file mode 100644 index 0258028ea..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package perf - -import ( - "fmt" - "strconv" - "testing" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" -) - -func TestTimer(t *testing.T) { - tr := NewTimer() - tr.Stop("hiyo") - tr.Stop("hiyo") - t.Log(em.Get("hiyo").(*buckets)) -} - -func BenchmarkStopWarm(b *testing.B) { - tr := NewTimer() - for range iter.N(b.N) { - tr.Stop("a") - } -} - -func BenchmarkStopCold(b *testing.B) { - tr := NewTimer() - for i := range iter.N(b.N) { - tr.Stop(strconv.FormatInt(int64(i), 10)) - } -} - -func TestExponent(t *testing.T) { - for _, c := range []struct { - e int - d time.Duration - }{ - {-1, 10 * time.Millisecond}, - {-2, 5 * time.Millisecond}, - {-2, time.Millisecond}, - {-3, 500 * time.Microsecond}, - {-3, 100 * time.Microsecond}, - } { - tr := NewTimer() - time.Sleep(c.d) - assert.Equal(t, c.e, bucketExponent(tr.Stop(fmt.Sprintf("%d", c.e))), "%s", c.d) - } - assert.Equal(t, `{"-1": 1}`, em.Get("-1").String()) - assert.Equal(t, `{"-2": 2}`, em.Get("-2").String()) - assert.Equal(t, `{"-3": 2}`, em.Get("-3").String()) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub.go deleted file mode 100644 index f92338590..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub.go +++ /dev/null @@ -1,92 +0,0 @@ -package pubsub - -import ( - "sync" -) - -type PubSub struct { - mu sync.Mutex - next chan item - closed bool -} - -type item struct { - value interface{} - next chan item -} - -type Subscription struct { - next chan item - Values chan interface{} - mu sync.Mutex - closed chan struct{} -} - -func NewPubSub() (ret *PubSub) { - return &PubSub{ - next: make(chan item, 1), - } -} - -func (me *PubSub) Publish(v interface{}) { - next := make(chan item, 1) - i := item{v, next} - me.mu.Lock() - me.next <- i - me.next = next - me.mu.Unlock() -} - -func (me *Subscription) Close() { - me.mu.Lock() - defer me.mu.Unlock() - select { - case <-me.closed: - default: - close(me.closed) - } -} - -func (me *Subscription) runner() { - defer close(me.Values) - for { - select { - case i, ok := <-me.next: - if !ok { - me.Close() - return - } - me.next <- i - me.next = i.next - select { - case me.Values <- i.value: - case <-me.closed: - return - } - case <-me.closed: - return - } - } -} - -func (me *PubSub) Subscribe() (ret *Subscription) { - ret = &Subscription{ - closed: make(chan struct{}), - Values: make(chan interface{}), - } - me.mu.Lock() - ret.next = me.next - me.mu.Unlock() - go ret.runner() - return -} - -func (me *PubSub) Close() { - me.mu.Lock() - defer me.mu.Unlock() - if me.closed { - return - } - close(me.next) - me.closed = true -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go deleted file mode 100644 index 87c998617..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package pubsub - -import ( - "sync" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" -) - -func TestDoubleClose(t *testing.T) { - ps := NewPubSub() - ps.Close() - ps.Close() -} - -func testBroadcast(t testing.TB, subs, vals int) { - ps := NewPubSub() - var wg sync.WaitGroup - for range iter.N(subs) { - wg.Add(1) - s := ps.Subscribe() - go func() { - defer wg.Done() - var e int - for i := range s.Values { - assert.Equal(t, e, i.(int)) - e++ - } - assert.Equal(t, vals, e) - }() - } - for i := range iter.N(vals) { - ps.Publish(i) - } - ps.Close() - wg.Wait() -} - -func TestBroadcast(t *testing.T) { - testBroadcast(t, 100, 10) -} - -func BenchmarkBroadcast(b *testing.B) { - for range iter.N(b.N) { - testBroadcast(b, 10, 1000) - } -} - -func TestCloseSubscription(t *testing.T) { - ps := NewPubSub() - ps.Publish(1) - s := ps.Subscribe() - select { - case <-s.Values: - t.FailNow() - default: - } - ps.Publish(2) - s2 := ps.Subscribe() - ps.Publish(3) - require.Equal(t, 2, <-s.Values) - require.EqualValues(t, 3, <-s.Values) - s.Close() - _, ok := <-s.Values - require.False(t, ok) - ps.Publish(4) - ps.Close() - require.Equal(t, 3, <-s2.Values) - require.Equal(t, 4, <-s2.Values) - require.Nil(t, <-s2.Values) - s2.Close() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle.go deleted file mode 100644 index 63d499767..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle.go +++ /dev/null @@ -1,46 +0,0 @@ -package missinggo - -// A RunLengthEncoder counts successive duplicate elements and emits the -// element and the run length when the element changes or the encoder is -// flushed. -type RunLengthEncoder interface { - // Add a series of identical elements to the stream. - Append(element interface{}, count uint64) - // Emit the current element and its count if non-zero without waiting for - // the element to change. - Flush() -} - -type runLengthEncoder struct { - eachRun func(element interface{}, count uint64) - element interface{} - count uint64 -} - -// Creates a new RunLengthEncoder. eachRun is called when an element and its -// count is emitted, per the RunLengthEncoder interface. -func NewRunLengthEncoder(eachRun func(element interface{}, count uint64)) RunLengthEncoder { - return &runLengthEncoder{ - eachRun: eachRun, - } -} - -func (me *runLengthEncoder) Append(element interface{}, count uint64) { - if element == me.element { - me.count += count - return - } - if me.count != 0 { - me.eachRun(me.element, me.count) - } - me.count = count - me.element = element -} - -func (me *runLengthEncoder) Flush() { - if me.count == 0 { - return - } - me.eachRun(me.element, me.count) - me.count = 0 -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle_test.go deleted file mode 100644 index 4e923f6fb..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/rle_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package missinggo_test - -import ( - "fmt" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -func ExampleNewRunLengthEncoder() { - var s string - rle := missinggo.NewRunLengthEncoder(func(e interface{}, count uint64) { - s += fmt.Sprintf("%d%c", count, e) - }) - for _, e := range "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW" { - rle.Append(e, 1) - } - rle.Flush() - fmt.Println(s) - // Output: 12W1B12W3B24W1B14W -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/singleflight.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/singleflight.go deleted file mode 100644 index 7a6e2996f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/singleflight.go +++ /dev/null @@ -1,39 +0,0 @@ -package missinggo - -import "sync" - -type ongoing struct { - do sync.Mutex - users int -} - -type SingleFlight struct { - mu sync.Mutex - ongoing map[string]*ongoing -} - -func (me *SingleFlight) Lock(id string) { - me.mu.Lock() - on, ok := me.ongoing[id] - if !ok { - on = new(ongoing) - if me.ongoing == nil { - me.ongoing = make(map[string]*ongoing) - } - me.ongoing[id] = on - } - on.users++ - me.mu.Unlock() - on.do.Lock() -} - -func (me *SingleFlight) Unlock(id string) { - me.mu.Lock() - on := me.ongoing[id] - on.do.Unlock() - on.users-- - if on.users == 0 { - delete(me.ongoing, id) - } - me.mu.Unlock() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/sync.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/sync.go deleted file mode 100644 index fc099bd63..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/sync.go +++ /dev/null @@ -1,11 +0,0 @@ -package missinggo - -import ( - "sync" -) - -type RWLocker interface { - sync.Locker - RLock() - RUnlock() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/url.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/url.go deleted file mode 100644 index 5f01eeee6..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/url.go +++ /dev/null @@ -1,30 +0,0 @@ -package missinggo - -import ( - "net/http" - "net/url" -) - -// Deep copies a URL. -func CopyURL(u *url.URL) (ret *url.URL) { - ret = new(url.URL) - *ret = *u - if u.User != nil { - ret.User = new(url.Userinfo) - *ret.User = *u.User - } - return -} - -// Reconstructs the URL that would have produced the given Request. -// Request.URLs are not fully populated in http.Server handlers. -func RequestedURL(r *http.Request) (ret *url.URL) { - ret = CopyURL(r.URL) - ret.Host = r.Host - if r.TLS != nil { - ret.Scheme = "https" - } else { - ret.Scheme = "http" - } - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf.go deleted file mode 100644 index 5552c61cd..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf.go +++ /dev/null @@ -1,51 +0,0 @@ -package missinggo - -import ( - "log" - "runtime" - "sync" - "sync/atomic" -) - -const debug = false - -// A Wolf represents some event that becomes less and less interesting as it -// occurs. Call CryHeard to see if we should pay attention this time. -type Wolf struct { - cries uint64 -} - -// Returns true less and less often. Convenient for exponentially decreasing -// the amount of noise due to errors. -func (me *Wolf) CryHeard() bool { - n := atomic.AddUint64(&me.cries, 1) - return n&(n-1) == 0 -} - -var ( - mu sync.Mutex - wolves map[uintptr]*Wolf -) - -// Calls CryHeard() on a Wolf that is unique to the callers program counter. -// i.e. every CryHeard() expression has its own Wolf. -func CryHeard() bool { - pc, file, line, ok := runtime.Caller(1) - if debug { - log.Println(pc, file, line, ok) - } - if !ok { - return true - } - mu.Lock() - if wolves == nil { - wolves = make(map[uintptr]*Wolf) - } - w, ok := wolves[pc] - if !ok { - w = new(Wolf) - wolves[pc] = w - } - mu.Unlock() - return w.CryHeard() -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go deleted file mode 100644 index f920c237f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package missinggo - -import ( - "testing" - - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" -) - -func cryHeard() bool { - return CryHeard() -} - -func TestCrySameLocation(t *testing.T) { - require.True(t, cryHeard()) - require.True(t, cryHeard()) - require.False(t, cryHeard()) - require.True(t, cryHeard()) - require.False(t, cryHeard()) - require.False(t, cryHeard()) - require.False(t, cryHeard()) - require.True(t, cryHeard()) -} - -func TestCryDifferentLocations(t *testing.T) { - require.True(t, CryHeard()) - require.True(t, CryHeard()) - require.True(t, CryHeard()) - require.True(t, CryHeard()) - require.True(t, CryHeard()) -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/LICENSE b/Godeps/_workspace/src/github.com/anacrolix/utp/LICENSE deleted file mode 100644 index be2cc4dfb..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/LICENSE +++ /dev/null @@ -1,362 +0,0 @@ -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. diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/README.md b/Godeps/_workspace/src/github.com/anacrolix/utp/README.md deleted file mode 100644 index 01c049e33..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# utp -[![GoDoc](https://godoc.org/github.com/anacrolix/utp?status.svg)](https://godoc.org/github.com/anacrolix/utp) -[![Build Status](https://drone.io/github.com/anacrolix/utp/status.png)](https://drone.io/github.com/anacrolix/utp/latest) - -Package utp implements uTP, the micro transport protocol as used with Bittorrent. It opts for simplicity and reliability over strict adherence to the (poor) spec. - -## Supported - - * Multiple uTP connections switched on a single PacketConn, including those initiated locally. - * Raw access to the PacketConn for non-uTP purposes, like sharing the PacketConn with a DHT implementation. - -## Implementation characteristics - - * Receive window size is used to limit out of order packets received. - * There is no MTU path discovery. The minimum size is always used. - * A fixed 64 slot selective ack window is used in both sending and receiving. - * All received non-ACK packets are ACKed in response. - -Patches welcomed. diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go b/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go deleted file mode 100644 index f5937e12f..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "io" - "log" - "net" - "os" - "os/signal" - - "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/utp" -) - -func main() { - defer envpprof.Stop() - listen := flag.Bool("l", false, "listen") - port := flag.Int("p", 0, "port to listen on") - flag.Parse() - var ( - conn net.Conn - err error - ) - if *listen { - s, err := utp.NewSocket("udp", fmt.Sprintf(":%d", *port)) - if err != nil { - log.Fatal(err) - } - defer s.Close() - conn, err = s.Accept() - if err != nil { - log.Fatal(err) - } - } else { - conn, err = utp.Dial(net.JoinHostPort(flag.Arg(0), flag.Arg(1))) - if err != nil { - log.Fatal(err) - } - } - defer conn.Close() - go func() { - sig := make(chan os.Signal, 1) - signal.Notify(sig, os.Interrupt) - <-sig - conn.Close() - }() - writerDone := make(chan struct{}) - go func() { - defer close(writerDone) - written, err := io.Copy(conn, os.Stdin) - if err != nil { - conn.Close() - log.Fatalf("error after writing %d bytes: %s", written, err) - } - log.Printf("wrote %d bytes", written) - conn.Close() - }() - n, err := io.Copy(os.Stdout, conn) - if err != nil { - log.Fatal(err) - } - log.Printf("received %d bytes", n) - // <-writerDone -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/pingpong b/Godeps/_workspace/src/github.com/anacrolix/utp/pingpong deleted file mode 100644 index 0a9333e75..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/pingpong +++ /dev/null @@ -1,61 +0,0 @@ -# This shell script uses nc-like executables to send and receive the file at -# $1, and prints the checksums. 3 such executables are -# github.com/h2so5/utp/ucat, invoked as h2so5-ucat, libutp-ucat, which is the -# ucat or ucat-static generated by the C++ libutp, and lastly, ./cmd/ucat from -# this repository. A good file in my experiments is no more than a few 100MB, -# or you'll be waiting a while. - -set -eu -# set -x - -# Passed to invocations of godo for package ./cmd/ucat. -#GODOFLAGS=-race - -#export GO_UTP_PACKET_DROP=0.1 -export GOPPROF= - -# Invokes the implementation to test against. If there's an arg, then it's -# expected to listen. -function other_ucat() { - if [[ $# != 0 ]]; then - libutp-ucat -l -p 4000 - # h2so5-ucat -l :4000 - else - libutp-ucat localhost 4000 - # h2so5-ucat localhost:4000 - fi -} - -# Check what the correct result is. -md5 "$1" - -rate() { - pv -a -W -b -} - -echo 'utp->other_ucat' -# Send from this uTP implementation to another client. -other_ucat -l | rate | md5 & -# sleep 1 -godo ${GODOFLAGS-} ./cmd/ucat localhost 4000 < "$1" -wait - -echo 'other_ucat->utp' -# Send from the other implementation, to this one. -GO_UTP_LOGGING=0 GOPPROF= godo ${GODOFLAGS-} ./cmd/ucat -l -p 4000 | rate | md5 & -# Never receive from h2so5's ucat without a small sleep first. Don't know why. -# sleep 1 -other_ucat < "$1" -wait - -echo 'libutp->libutp' -libutp-ucat -l -p 4000 | rate | md5 & -libutp-ucat localhost 4000 < "$1" -wait - -echo 'utp->utp' -godo ./cmd/ucat -l -p 4000 | rate | md5 & -godo ./cmd/ucat localhost 4000 < "$1" -wait - -# Now check the hashes match (yes you). diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/utp.go b/Godeps/_workspace/src/github.com/anacrolix/utp/utp.go deleted file mode 100644 index 205c8b278..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/utp.go +++ /dev/null @@ -1,1461 +0,0 @@ -// Package utp implements uTP, the micro transport protocol as used with -// Bittorrent. It opts for simplicity and reliability over strict adherence to -// the (poor) spec. It allows using the underlying OS-level transport despite -// dispatching uTP on top to allow for example, shared socket use with DHT. -// Additionally, multiple uTP connections can share the same OS socket, to -// truly realize uTP's claim to be light on system and network switching -// resources. -// -// Socket is a wrapper of net.UDPConn, and performs dispatching of uTP packets -// to attached uTP Conns. Dial and Accept is done via Socket. Conn implements -// net.Conn over uTP, via aforementioned Socket. -package utp - -import ( - "encoding/binary" - "errors" - "expvar" - "fmt" - "io" - "log" - "math/rand" - "net" - "os" - "strconv" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/jitter" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" -) - -const ( - // Maximum received SYNs that haven't been accepted. If more SYNs are - // received, a pseudo randomly selected SYN is replied to with a reset to - // make room. - backlog = 50 - - // IPv6 min MTU is 1280, -40 for IPv6 header, and ~8 for fragment header? - minMTU = 1232 - recvWindow = 0x8000 // 32KiB - // uTP header of 20, +2 for the next extension, and 8 bytes of selective - // ACK. - maxHeaderSize = 30 - maxPayloadSize = minMTU - maxHeaderSize - maxRecvSize = 0x2000 - - // Maximum out-of-order packets to buffer. - maxUnackedInbound = 64 - - // If an send isn't acknowledged after this period, its connection is - // destroyed. There are resends during this period. - sendTimeout = 15 * time.Second -) - -var ( - ackSkippedResends = expvar.NewInt("utpAckSkippedResends") - // Inbound packets processed by a Conn. - deliveriesProcessed = expvar.NewInt("utpDeliveriesProcessed") - sentStatePackets = expvar.NewInt("utpSentStatePackets") - unusedReads = expvar.NewInt("utpUnusedReads") - sendBufferPool = sync.Pool{ - New: func() interface{} { return make([]byte, minMTU) }, - } -) - -type deadlineCallback struct { - deadline time.Time - timer *time.Timer - callback func() - inited bool -} - -func (me *deadlineCallback) deadlineExceeded() bool { - return !me.deadline.IsZero() && !time.Now().Before(me.deadline) -} - -func (me *deadlineCallback) updateTimer() { - if me.timer != nil { - me.timer.Stop() - } - if me.deadline.IsZero() { - return - } - if me.callback == nil { - panic("deadline callback is nil") - } - me.timer = time.AfterFunc(me.deadline.Sub(time.Now()), me.callback) -} - -func (me *deadlineCallback) setDeadline(t time.Time) { - me.deadline = t - me.updateTimer() -} - -func (me *deadlineCallback) setCallback(f func()) { - me.callback = f - me.updateTimer() -} - -type connDeadlines struct { - // mu sync.Mutex - read, write deadlineCallback -} - -func (c *connDeadlines) SetDeadline(t time.Time) error { - c.read.setDeadline(t) - c.write.setDeadline(t) - return nil -} - -func (c *connDeadlines) SetReadDeadline(t time.Time) error { - c.read.setDeadline(t) - return nil -} - -func (c *connDeadlines) SetWriteDeadline(t time.Time) error { - c.write.setDeadline(t) - return nil -} - -// Strongly-type guarantee of resolved network address. -type resolvedAddrStr string - -// Uniquely identifies any uTP connection on top of the underlying packet -// stream. -type connKey struct { - remoteAddr resolvedAddrStr - connID uint16 -} - -// A Socket wraps a net.PacketConn, diverting uTP packets to its child uTP -// Conns. -type Socket struct { - mu sync.RWMutex - event sync.Cond - pc net.PacketConn - conns map[connKey]*Conn - backlog map[syn]struct{} - reads chan read - closing chan struct{} - - unusedReads chan read - connDeadlines - // If a read error occurs on the underlying net.PacketConn, it is put - // here. This is because reading is done in its own goroutine to dispatch - // to uTP Conns. - ReadErr error -} - -type read struct { - data []byte - from net.Addr -} - -type syn struct { - seq_nr, conn_id uint16 - addr string -} - -const ( - extensionTypeSelectiveAck = 1 -) - -type extensionField struct { - Type byte - Bytes []byte -} - -type header struct { - Type st - Version int - ConnID uint16 - Timestamp uint32 - TimestampDiff uint32 - WndSize uint32 - SeqNr uint16 - AckNr uint16 - Extensions []extensionField -} - -var ( - mu sync.RWMutex - logLevel = 0 - artificialPacketDropChance = 0.0 -) - -func init() { - logLevel, _ = strconv.Atoi(os.Getenv("GO_UTP_LOGGING")) - fmt.Sscanf(os.Getenv("GO_UTP_PACKET_DROP"), "%f", &artificialPacketDropChance) -} - -var ( - errClosed = errors.New("closed") - errNotImplemented = errors.New("not implemented") - errTimeout net.Error = timeoutError{"i/o timeout"} - errAckTimeout = timeoutError{"timed out waiting for ack"} -) - -type timeoutError struct { - msg string -} - -func (me timeoutError) Timeout() bool { return true } -func (me timeoutError) Error() string { return me.msg } -func (me timeoutError) Temporary() bool { return false } - -func unmarshalExtensions(_type byte, b []byte) (n int, ef []extensionField, err error) { - for _type != 0 { - if _type != extensionTypeSelectiveAck { - // An extension type that is not known to us. Generally we're - // unmarshalling an packet that isn't actually uTP but we don't - // yet know for sure until we try to deliver it. - - // logonce.Stderr.Printf("utp extension %d", _type) - } - if len(b) < 2 || len(b) < int(b[1])+2 { - err = fmt.Errorf("buffer ends prematurely: %x", b) - return - } - ef = append(ef, extensionField{ - Type: _type, - Bytes: append([]byte{}, b[2:int(b[1])+2]...), - }) - _type = b[0] - n += 2 + int(b[1]) - b = b[2+int(b[1]):] - } - return -} - -var errInvalidHeader = errors.New("invalid header") - -func (h *header) Unmarshal(b []byte) (n int, err error) { - h.Type = st(b[0] >> 4) - h.Version = int(b[0] & 0xf) - if h.Type > stMax || h.Version != 1 { - err = errInvalidHeader - return - } - n, h.Extensions, err = unmarshalExtensions(b[1], b[20:]) - if err != nil { - return - } - h.ConnID = binary.BigEndian.Uint16(b[2:4]) - h.Timestamp = binary.BigEndian.Uint32(b[4:8]) - h.TimestampDiff = binary.BigEndian.Uint32(b[8:12]) - h.WndSize = binary.BigEndian.Uint32(b[12:16]) - h.SeqNr = binary.BigEndian.Uint16(b[16:18]) - h.AckNr = binary.BigEndian.Uint16(b[18:20]) - n += 20 - return -} - -func (h *header) Marshal() (ret []byte) { - hLen := 20 + func() (ret int) { - for _, ext := range h.Extensions { - ret += 2 + len(ext.Bytes) - } - return - }() - ret = sendBufferPool.Get().([]byte)[:hLen:minMTU] - // ret = make([]byte, hLen, minMTU) - p := ret // Used for manipulating ret. - p[0] = byte(h.Type<<4 | 1) - binary.BigEndian.PutUint16(p[2:4], h.ConnID) - binary.BigEndian.PutUint32(p[4:8], h.Timestamp) - binary.BigEndian.PutUint32(p[8:12], h.TimestampDiff) - binary.BigEndian.PutUint32(p[12:16], h.WndSize) - binary.BigEndian.PutUint16(p[16:18], h.SeqNr) - binary.BigEndian.PutUint16(p[18:20], h.AckNr) - // Pointer to the last type field so the next extension can set it. - _type := &p[1] - // We're done with the basic header. - p = p[20:] - for _, ext := range h.Extensions { - *_type = ext.Type - // The next extension's type will go here. - _type = &p[0] - p[1] = uint8(len(ext.Bytes)) - if int(p[1]) != copy(p[2:], ext.Bytes) { - panic("unexpected extension length") - } - p = p[2+len(ext.Bytes):] - } - if len(p) != 0 { - panic("header length changed") - } - return -} - -var ( - _ net.Listener = &Socket{} - _ net.PacketConn = &Socket{} -) - -const ( - csInvalid = iota - csSynSent - csConnected - csDestroy -) - -type st int - -func (me st) String() string { - switch me { - case stData: - return "stData" - case stFin: - return "stFin" - case stState: - return "stState" - case stReset: - return "stReset" - case stSyn: - return "stSyn" - default: - panic(fmt.Sprintf("%d", me)) - } -} - -const ( - stData st = 0 - stFin = 1 - stState = 2 - stReset = 3 - stSyn = 4 - - // Used for validating packet headers. - stMax = stSyn -) - -// Conn is a uTP stream and implements net.Conn. It owned by a Socket, which -// handles dispatching packets to and from Conns. -type Conn struct { - mu sync.Mutex - event sync.Cond - - recv_id, send_id uint16 - seq_nr, ack_nr uint16 - lastAck uint16 - lastTimeDiff uint32 - peerWndSize uint32 - - readBuf []byte - - socket *Socket - remoteAddr net.Addr - // The uTP timestamp. - startTimestamp uint32 - // When the conn was allocated. - created time.Time - // Callback to unregister Conn from a parent Socket. Should be called when - // no more packets will be handled. - detach func() - - cs int - gotFin bool - sentFin bool - err error - - unackedSends []*send - // Inbound payloads, the first is ack_nr+1. - inbound []recv - packetsIn chan packet - connDeadlines - latencies []time.Duration - pendingSendState bool - destroyed chan struct{} -} - -type send struct { - acked chan struct{} // Closed with Conn lock. - payloadSize uint32 - started time.Time - // This send was skipped in a selective ack. - resend func() - timedOut func() - conn *Conn - - mu sync.Mutex - acksSkipped int - resendTimer *time.Timer - numResends int -} - -func (s *send) Ack() (latency time.Duration) { - s.mu.Lock() - defer s.mu.Unlock() - s.resendTimer.Stop() - select { - case <-s.acked: - return - default: - close(s.acked) - } - latency = time.Since(s.started) - return -} - -type recv struct { - seen bool - data []byte - Type st -} - -var ( - _ net.Conn = &Conn{} -) - -func (c *Conn) age() time.Duration { - return time.Since(c.created) -} - -func (c *Conn) timestamp() uint32 { - return nowTimestamp() - c.startTimestamp -} - -func (c *Conn) connected() bool { - return c.cs == csConnected -} - -// addr is used to create a listening UDP conn which becomes the underlying -// net.PacketConn for the Socket. -func NewSocket(network, addr string) (s *Socket, err error) { - s = &Socket{ - backlog: make(map[syn]struct{}, backlog), - reads: make(chan read, 100), - closing: make(chan struct{}), - - unusedReads: make(chan read, 100), - } - s.event.L = &s.mu - s.pc, err = net.ListenPacket(network, addr) - if err != nil { - return - } - go s.reader() - go s.dispatcher() - return -} - -func packetDebugString(h *header, payload []byte) string { - return fmt.Sprintf("%s->%d: %q", h.Type, h.ConnID, payload) -} - -func (s *Socket) reader() { - defer close(s.reads) - var b [maxRecvSize]byte - for { - if s.pc == nil { - break - } - n, addr, err := s.pc.ReadFrom(b[:]) - if err != nil { - select { - case <-s.closing: - default: - s.ReadErr = err - } - return - } - var nilB []byte - s.reads <- read{append(nilB, b[:n:n]...), addr} - } -} - -func (s *Socket) unusedRead(read read) { - unusedReads.Add(1) - select { - case s.unusedReads <- read: - default: - // Drop the packet. - } -} - -func stringAddr(s string) net.Addr { - addr, err := net.ResolveUDPAddr("udp", s) - if err != nil { - panic(err) - } - return addr -} - -func (s *Socket) pushBacklog(syn syn) { - if _, ok := s.backlog[syn]; ok { - return - } - for k := range s.backlog { - if len(s.backlog) < backlog { - break - } - delete(s.backlog, k) - // A syn is sent on the remote's recv_id, so this is where we can send - // the reset. - s.reset(stringAddr(k.addr), k.seq_nr, k.conn_id) - } - s.backlog[syn] = struct{}{} - s.event.Broadcast() -} - -func (s *Socket) dispatcher() { - for { - select { - case read, ok := <-s.reads: - if !ok { - return - } - if len(read.data) < 20 { - s.unusedRead(read) - continue - } - s.dispatch(read) - } - } -} - -func (s *Socket) dispatch(read read) { - b := read.data - addr := read.from - var h header - hEnd, err := h.Unmarshal(b) - if logLevel >= 1 { - log.Printf("recvd utp msg: %s", packetDebugString(&h, b[hEnd:])) - } - if err != nil || h.Type > stMax || h.Version != 1 { - s.unusedRead(read) - return - } - s.mu.RLock() - c, ok := s.conns[connKey{resolvedAddrStr(addr.String()), func() (recvID uint16) { - recvID = h.ConnID - // If a SYN is resent, its connection ID field will be one lower - // than we expect. - if h.Type == stSyn { - recvID++ - } - return - }()}] - s.mu.RUnlock() - if ok { - if h.Type == stSyn { - if h.ConnID == c.send_id-2 { - // This is a SYN for connection that cannot exist locally. The - // connection the remote wants to establish here with the proposed - // recv_id, already has an existing connection that was dialled - // *out* from this socket, which is why the send_id is 1 higher, - // rather than 1 lower than the recv_id. - log.Print("resetting conflicting syn") - s.reset(addr, h.SeqNr, h.ConnID) - return - } else if h.ConnID != c.send_id { - panic("bad assumption") - } - } - c.deliver(h, b[hEnd:]) - return - } - if h.Type == stSyn { - if logLevel >= 1 { - log.Printf("adding SYN to backlog") - } - syn := syn{ - seq_nr: h.SeqNr, - conn_id: h.ConnID, - addr: addr.String(), - } - s.mu.Lock() - s.pushBacklog(syn) - s.mu.Unlock() - return - } else if h.Type != stReset { - // This is an unexpected packet. We'll send a reset, but also pass - // it on. - // log.Print("resetting unexpected packet") - // I don't think you can reset on the received packets ConnID if it isn't a SYN, as the send_id will differ in this case. - s.reset(addr, h.SeqNr, h.ConnID) - s.reset(addr, h.SeqNr, h.ConnID-1) - s.reset(addr, h.SeqNr, h.ConnID+1) - } - s.unusedRead(read) -} - -// Send a reset in response to a packet with the given header. -func (s *Socket) reset(addr net.Addr, ackNr, connId uint16) { - go s.writeTo((&header{ - Type: stReset, - Version: 1, - ConnID: connId, - AckNr: ackNr, - }).Marshal(), addr) -} - -// Attempt to connect to a remote uTP listener, creating a Socket just for -// this connection. -func Dial(addr string) (net.Conn, error) { - return DialTimeout(addr, 0) -} - -// Same as Dial with a timeout parameter. -func DialTimeout(addr string, timeout time.Duration) (nc net.Conn, err error) { - s, err := NewSocket("udp", ":0") - if err != nil { - return - } - return s.DialTimeout(addr, timeout) - -} - -// Return a recv_id that should be free. Handling the case where it isn't is -// deferred to a more appropriate function. -func (s *Socket) newConnID(remoteAddr resolvedAddrStr) (id uint16) { - // Rather than use math.Rand, which requires generating all the IDs up - // front and allocating a slice, we do it on the stack, generating the IDs - // only as required. To do this, we use the fact that the array is - // default-initialized. IDs that are 0, are actually their index in the - // array. IDs that are non-zero, are +1 from their intended ID. - var idsBack [0x10000]int - ids := idsBack[:] - for len(ids) != 0 { - // Pick the next ID from the untried ids. - i := rand.Intn(len(ids)) - id = uint16(ids[i]) - // If it's zero, then treat it as though the index i was the ID. - // Otherwise the value we get is the ID+1. - if id == 0 { - id = uint16(i) - } else { - id-- - } - // Check there's no connection using this ID for its recv_id... - _, ok1 := s.conns[connKey{remoteAddr, id}] - // and if we're connecting to our own Socket, that there isn't a Conn - // already receiving on what will correspond to our send_id. Note that - // we just assume that we could be connecting to our own Socket. This - // will halve the available connection IDs to each distinct remote - // address. Presumably that's ~0x8000, down from ~0x10000. - _, ok2 := s.conns[connKey{remoteAddr, id + 1}] - _, ok4 := s.conns[connKey{remoteAddr, id - 1}] - if !ok1 && !ok2 && !ok4 { - return - } - // The set of possible IDs is shrinking. The highest one will be lost, so - // it's moved to the location of the one we just tried. - ids[i] = len(ids) // Conveniently already +1. - // And shrink. - ids = ids[:len(ids)-1] - } - return -} - -func (c *Conn) sendPendingState() { - if !c.pendingSendState { - return - } - c.sendState() -} - -func (s *Socket) newConn(addr net.Addr) (c *Conn) { - c = &Conn{ - socket: s, - remoteAddr: addr, - startTimestamp: nowTimestamp(), - created: time.Now(), - packetsIn: make(chan packet, 100), - destroyed: make(chan struct{}), - } - c.event.L = &c.mu - c.mu.Lock() - c.connDeadlines.read.setCallback(func() { - c.mu.Lock() - c.event.Broadcast() - c.mu.Unlock() - }) - c.connDeadlines.write.setCallback(func() { - c.mu.Lock() - c.event.Broadcast() - c.mu.Unlock() - }) - c.mu.Unlock() - go c.deliveryProcessor() - return -} - -func (s *Socket) Dial(addr string) (net.Conn, error) { - return s.DialTimeout(addr, 0) -} - -func (s *Socket) DialTimeout(addr string, timeout time.Duration) (nc net.Conn, err error) { - netAddr, err := net.ResolveUDPAddr("udp", addr) - if err != nil { - return - } - - s.mu.Lock() - c := s.newConn(netAddr) - c.recv_id = s.newConnID(resolvedAddrStr(netAddr.String())) - c.send_id = c.recv_id + 1 - if logLevel >= 1 { - log.Printf("dial registering addr: %s", netAddr.String()) - } - if !s.registerConn(c.recv_id, resolvedAddrStr(netAddr.String()), c) { - err = errors.New("couldn't register new connection") - log.Println(c.recv_id, netAddr.String()) - for k, c := range s.conns { - log.Println(k, c, c.age()) - } - log.Printf("that's %d connections", len(s.conns)) - } - s.mu.Unlock() - if err != nil { - return - } - - connErr := make(chan error, 1) - go func() { - connErr <- c.connect() - }() - var timeoutCh <-chan time.Time - if timeout != 0 { - timeoutCh = time.After(timeout) - } - select { - case err = <-connErr: - case <-timeoutCh: - c.Close() - err = errTimeout - } - if err == nil { - nc = c - } - return -} - -func (c *Conn) wndSize() uint32 { - if len(c.inbound) > maxUnackedInbound/2 { - return 0 - } - var buffered int - for _, r := range c.inbound { - buffered += len(r.data) - } - buffered += len(c.readBuf) - if buffered >= recvWindow { - return 0 - } - return recvWindow - uint32(buffered) -} - -func nowTimestamp() uint32 { - return uint32(time.Now().UnixNano() / int64(time.Microsecond)) -} - -// Send the given payload with an up to date header. -func (c *Conn) send(_type st, connID uint16, payload []byte, seqNr uint16) (err error) { - // Always selectively ack the first 64 packets. Don't bother with rest for - // now. - selAck := selectiveAckBitmask(make([]byte, 8)) - for i := 1; i < 65; i++ { - if len(c.inbound) <= i { - break - } - if c.inbound[i].seen { - selAck.SetBit(i - 1) - } - } - h := header{ - Type: _type, - Version: 1, - ConnID: connID, - SeqNr: seqNr, - AckNr: c.ack_nr, - WndSize: c.wndSize(), - Timestamp: c.timestamp(), - TimestampDiff: c.lastTimeDiff, - // Currently always send an 8 byte selective ack. - Extensions: []extensionField{{ - Type: extensionTypeSelectiveAck, - Bytes: selAck, - }}, - } - p := h.Marshal() - // Extension headers are currently fixed in size. - if len(p) != maxHeaderSize { - panic("header has unexpected size") - } - p = append(p, payload...) - if logLevel >= 1 { - log.Printf("writing utp msg to %s: %s", c.remoteAddr, packetDebugString(&h, payload)) - } - n1, err := c.socket.writeTo(p, c.remoteAddr) - if err != nil { - return - } - if n1 != len(p) { - panic(n1) - } - c.unpendSendState() - return -} - -func (me *Conn) unpendSendState() { - me.pendingSendState = false -} - -func (c *Conn) pendSendState() { - c.pendingSendState = true -} - -func (me *Socket) writeTo(b []byte, addr net.Addr) (n int, err error) { - mu.RLock() - apdc := artificialPacketDropChance - mu.RUnlock() - if apdc != 0 { - if rand.Float64() < apdc { - n = len(b) - return - } - } - n, err = me.pc.WriteTo(b, addr) - return -} - -func (s *send) timeoutResend() { - select { - case <-s.acked: - return - default: - } - if time.Since(s.started) >= sendTimeout { - s.timedOut() - return - } - s.conn.mu.Lock() - rt := s.conn.resendTimeout() - s.conn.mu.Unlock() - go s.resend() - s.mu.Lock() - s.numResends++ - s.resendTimer.Reset(rt) - s.mu.Unlock() -} - -func (me *Conn) writeSyn() (err error) { - if me.cs != csInvalid { - panic(me.cs) - } - _, err = me.write(stSyn, me.recv_id, nil, me.seq_nr) - return -} - -func (c *Conn) write(_type st, connID uint16, payload []byte, seqNr uint16) (n int, err error) { - switch _type { - case stSyn, stFin, stData: - default: - panic(_type) - } - switch c.cs { - case csConnected, csSynSent, csInvalid: - default: - panic(c.cs) - } - if c.sentFin { - panic(c) - } - if len(payload) > maxPayloadSize { - payload = payload[:maxPayloadSize] - } - err = c.send(_type, connID, payload, seqNr) - if err != nil { - return - } - n = len(payload) - // Copy payload so caller to write can continue to use the buffer. - if payload != nil { - payload = append(sendBufferPool.Get().([]byte)[:0:minMTU], payload...) - } - send := &send{ - acked: make(chan struct{}), - payloadSize: uint32(len(payload)), - started: time.Now(), - resend: func() { - c.mu.Lock() - err := c.send(_type, connID, payload, seqNr) - if err != nil { - log.Printf("error resending packet: %s", err) - } - c.mu.Unlock() - }, - timedOut: func() { - c.mu.Lock() - c.destroy(errAckTimeout) - c.mu.Unlock() - }, - conn: c, - } - send.mu.Lock() - send.resendTimer = time.AfterFunc(c.resendTimeout(), send.timeoutResend) - send.mu.Unlock() - c.unackedSends = append(c.unackedSends, send) - c.seq_nr++ - return -} - -func (c *Conn) latency() (ret time.Duration) { - if len(c.latencies) == 0 { - // Sort of the p95 of latencies? - return 200 * time.Millisecond - } - for _, l := range c.latencies { - ret += l - } - ret = (ret + time.Duration(len(c.latencies)) - 1) / time.Duration(len(c.latencies)) - return -} - -func (c *Conn) numUnackedSends() (num int) { - for _, s := range c.unackedSends { - select { - case <-s.acked: - default: - num++ - } - } - return -} - -func (c *Conn) cur_window() (window uint32) { - for _, s := range c.unackedSends { - select { - case <-s.acked: - default: - window += s.payloadSize - } - } - return -} - -func (c *Conn) sendState() { - c.send(stState, c.send_id, nil, c.seq_nr) - sentStatePackets.Add(1) -} - -func seqLess(a, b uint16) bool { - if b < 0x8000 { - return a < b || a >= b-0x8000 - } else { - return a < b && a >= b-0x8000 - } -} - -// Ack our send with the given sequence number. -func (c *Conn) ack(nr uint16) { - if !seqLess(c.lastAck, nr) { - // Already acked. - return - } - i := nr - c.lastAck - 1 - if int(i) >= len(c.unackedSends) { - log.Printf("got ack ahead of syn (%x > %x)", nr, c.seq_nr-1) - return - } - latency := c.unackedSends[i].Ack() - if latency != 0 { - c.latencies = append(c.latencies, latency) - if len(c.latencies) > 10 { - c.latencies = c.latencies[len(c.latencies)-10:] - } - } - for { - if len(c.unackedSends) == 0 { - break - } - select { - case <-c.unackedSends[0].acked: - default: - // Can't trim unacked sends any further. - return - } - // Trim the front of the unacked sends. - c.unackedSends = c.unackedSends[1:] - c.lastAck++ - } - c.event.Broadcast() -} - -func (c *Conn) ackTo(nr uint16) { - if !seqLess(nr, c.seq_nr) { - return - } - for seqLess(c.lastAck, nr) { - c.ack(c.lastAck + 1) - } -} - -type selectiveAckBitmask []byte - -func (me selectiveAckBitmask) NumBits() int { - return len(me) * 8 -} - -func (me selectiveAckBitmask) SetBit(index int) { - me[index/8] |= 1 << uint(index%8) -} - -func (me selectiveAckBitmask) BitIsSet(index int) bool { - return me[index/8]>>uint(index%8)&1 == 1 -} - -// Return the send state for the sequence number. Returns nil if there's no -// outstanding send for that sequence number. -func (c *Conn) seqSend(seqNr uint16) *send { - if !seqLess(c.lastAck, seqNr) { - // Presumably already acked. - return nil - } - i := int(seqNr - c.lastAck - 1) - if i >= len(c.unackedSends) { - // No such send. - return nil - } - return c.unackedSends[i] -} - -func (c *Conn) resendTimeout() time.Duration { - l := c.latency() - if l < 10*time.Millisecond { - l = 10 * time.Millisecond - } - ret := jitter.Duration(3*l, l) - // log.Print(ret) - return ret -} - -func (c *Conn) ackSkipped(seqNr uint16) { - send := c.seqSend(seqNr) - if send == nil { - return - } - send.mu.Lock() - defer send.mu.Unlock() - send.acksSkipped++ - switch send.acksSkipped { - case 3, 60: - ackSkippedResends.Add(1) - go send.resend() - send.resendTimer.Reset(c.resendTimeout()) - default: - } -} - -type packet struct { - h header - payload []byte -} - -func (c *Conn) deliver(h header, payload []byte) { - c.packetsIn <- packet{h, payload} -} - -func (c *Conn) deliveryProcessor() { - for { - select { - case p := <-c.packetsIn: - c.processDelivery(p.h, p.payload) - timeout := time.After(500 * time.Microsecond) - batched: - for { - select { - case p := <-c.packetsIn: - c.processDelivery(p.h, p.payload) - case <-timeout: - break batched - } - } - c.mu.Lock() - c.sendPendingState() - c.mu.Unlock() - case <-c.destroyed: - return - } - } -} - -func (c *Conn) processDelivery(h header, payload []byte) { - deliveriesProcessed.Add(1) - c.mu.Lock() - defer c.mu.Unlock() - defer c.event.Broadcast() - c.assertHeader(h) - c.peerWndSize = h.WndSize - c.applyAcks(h) - if h.Timestamp == 0 { - c.lastTimeDiff = 0 - } else { - c.lastTimeDiff = c.timestamp() - h.Timestamp - } - - // We want this connection destroyed, and our peer has acked everything. - if c.sentFin && len(c.unackedSends) == 0 { - // log.Print("gracefully completed") - c.destroy(nil) - return - } - if h.Type == stReset { - c.destroy(errors.New("peer reset")) - return - } - if c.cs == csSynSent { - if h.Type != stState { - return - } - c.changeState(csConnected) - c.ack_nr = h.SeqNr - 1 - return - } - if h.Type == stState { - return - } - c.pendSendState() - if !seqLess(c.ack_nr, h.SeqNr) { - // Already received this packet. - return - } - inboundIndex := int(h.SeqNr - c.ack_nr - 1) - if inboundIndex < len(c.inbound) && c.inbound[inboundIndex].seen { - // Already received this packet. - return - } - // Derived from running in production: - // grep -oP '(?<=packet out of order, index=)\d+' log | sort -n | uniq -c - // 64 should correspond to 8 bytes of selective ack. - if inboundIndex >= maxUnackedInbound { - // Discard packet too far ahead. - if missinggo.CryHeard() { - // I can't tell if this occurs due to bad peers, or something - // missing in the implementation. - log.Printf("received packet from %s %d ahead of next seqnr (%x > %x)", c.remoteAddr, inboundIndex, h.SeqNr, c.ack_nr+1) - } - return - } - // Extend inbound so the new packet has a place. - for inboundIndex >= len(c.inbound) { - c.inbound = append(c.inbound, recv{}) - } - c.inbound[inboundIndex] = recv{true, payload, h.Type} - c.processInbound() -} - -func (c *Conn) applyAcks(h header) { - c.ackTo(h.AckNr) - for _, ext := range h.Extensions { - switch ext.Type { - case extensionTypeSelectiveAck: - c.ackSkipped(h.AckNr + 1) - bitmask := selectiveAckBitmask(ext.Bytes) - for i := 0; i < bitmask.NumBits(); i++ { - if bitmask.BitIsSet(i) { - nr := h.AckNr + 2 + uint16(i) - // log.Printf("selectively acked %d", nr) - c.ack(nr) - } else { - c.ackSkipped(h.AckNr + 2 + uint16(i)) - } - } - } - } -} - -func (c *Conn) assertHeader(h header) { - if h.Type == stSyn { - if h.ConnID != c.send_id { - panic(fmt.Sprintf("%d != %d", h.ConnID, c.send_id)) - } - } else { - if h.ConnID != c.recv_id { - panic("erroneous delivery") - } - } -} - -func (c *Conn) processInbound() { - // Consume consecutive next packets. - for !c.gotFin && len(c.inbound) > 0 && c.inbound[0].seen { - c.ack_nr++ - p := c.inbound[0] - c.inbound = c.inbound[1:] - c.readBuf = append(c.readBuf, p.data...) - if p.Type == stFin { - c.gotFin = true - } - } -} - -func (c *Conn) waitAck(seq uint16) { - send := c.seqSend(seq) - if send == nil { - return - } - c.mu.Unlock() - defer c.mu.Lock() - <-send.acked - return -} - -func (c *Conn) changeState(cs int) { - // log.Println(c, "goes", c.cs, "->", cs) - c.cs = cs -} - -func (c *Conn) connect() error { - c.mu.Lock() - defer c.mu.Unlock() - c.seq_nr = 1 - err := c.writeSyn() - if err != nil { - return err - } - c.changeState(csSynSent) - if logLevel >= 2 { - log.Printf("sent syn") - } - // c.seq_nr++ - c.waitAck(1) - if c.err != nil { - err = c.err - } - c.event.Broadcast() - return err -} - -// Returns true if the connection was newly registered, false otherwise. -func (s *Socket) registerConn(recvID uint16, remoteAddr resolvedAddrStr, c *Conn) bool { - if s.conns == nil { - s.conns = make(map[connKey]*Conn) - } - key := connKey{remoteAddr, recvID} - if _, ok := s.conns[key]; ok { - return false - } - s.conns[key] = c - c.detach = func() { - s.mu.Lock() - defer s.mu.Unlock() - defer s.event.Broadcast() - if s.conns[key] != c { - panic("conn changed") - } - // log.Println("detached", key) - delete(s.conns, key) - if len(s.conns) == 0 { - s.pc.Close() - } - } - return true -} - -func (s *Socket) nextSyn() (syn syn, ok bool) { - s.mu.Lock() - defer s.mu.Unlock() - for { - for k := range s.backlog { - syn = k - delete(s.backlog, k) - ok = true - return - } - select { - case <-s.closing: - return - default: - } - s.event.Wait() - } -} - -// Accept and return a new uTP connection. -func (s *Socket) Accept() (c net.Conn, err error) { - for { - syn, ok := s.nextSyn() - if !ok { - err = errClosed - return - } - s.mu.Lock() - _c := s.newConn(stringAddr(syn.addr)) - _c.send_id = syn.conn_id - _c.recv_id = _c.send_id + 1 - _c.seq_nr = uint16(rand.Int()) - _c.lastAck = _c.seq_nr - 1 - _c.ack_nr = syn.seq_nr - _c.cs = csConnected - if !s.registerConn(_c.recv_id, resolvedAddrStr(syn.addr), _c) { - // SYN that triggered this accept duplicates existing connection. - // Ack again in case the SYN was a resend. - _c = s.conns[connKey{resolvedAddrStr(syn.addr), _c.recv_id}] - if _c.send_id != syn.conn_id { - panic(":|") - } - _c.sendState() - s.mu.Unlock() - continue - } - _c.sendState() - // _c.seq_nr++ - c = _c - s.mu.Unlock() - return - } -} - -// The address we're listening on for new uTP connections. -func (s *Socket) Addr() net.Addr { - return s.pc.LocalAddr() -} - -// Marks the Socket for close. Currently this just axes the underlying OS -// socket. -func (s *Socket) Close() (err error) { - s.mu.Lock() - defer s.mu.Unlock() - select { - case <-s.closing: - return - default: - } - s.event.Broadcast() - close(s.closing) - if len(s.conns) == 0 { - err = s.pc.Close() - } - return -} - -func (s *Socket) LocalAddr() net.Addr { - return s.pc.LocalAddr() -} - -func (s *Socket) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - read, ok := <-s.unusedReads - if !ok { - err = io.EOF - } - n = copy(p, read.data) - addr = read.from - return -} - -func (s *Socket) WriteTo(b []byte, addr net.Addr) (int, error) { - return s.pc.WriteTo(b, addr) -} - -func (c *Conn) writeFin() (err error) { - if c.sentFin { - return - } - _, err = c.write(stFin, c.send_id, nil, c.seq_nr) - if err != nil { - return - } - c.sentFin = true - c.event.Broadcast() - return -} - -func (c *Conn) destroy(reason error) { - if c.err != nil && reason != nil { - log.Printf("duplicate destroy call: %s", reason) - } - if c.cs == csDestroy { - return - } - close(c.destroyed) - c.writeFin() - c.changeState(csDestroy) - c.err = reason - c.event.Broadcast() - c.detach() - for _, s := range c.unackedSends { - s.Ack() - } -} - -func (c *Conn) Close() error { - c.mu.Lock() - defer c.mu.Unlock() - return c.writeFin() -} - -func (c *Conn) LocalAddr() net.Addr { - return c.socket.Addr() -} - -func (c *Conn) Read(b []byte) (n int, err error) { - c.mu.Lock() - defer c.mu.Unlock() - for { - if len(c.readBuf) != 0 { - break - } - if c.cs == csDestroy || c.gotFin || c.sentFin { - err = c.err - if err == nil { - err = io.EOF - } - return - } - if c.connDeadlines.read.deadlineExceeded() { - err = errTimeout - return - } - if logLevel >= 2 { - log.Printf("nothing to read, state=%d", c.cs) - } - c.event.Wait() - } - n = copy(b, c.readBuf) - c.readBuf = c.readBuf[n:] - - return -} - -func (c *Conn) RemoteAddr() net.Addr { - return c.remoteAddr -} - -func (c *Conn) String() string { - return fmt.Sprintf("", c.LocalAddr(), c.RemoteAddr(), c.recv_id) -} - -func (c *Conn) Write(p []byte) (n int, err error) { - c.mu.Lock() - defer c.mu.Unlock() - for len(p) != 0 { - for { - if c.sentFin { - err = io.ErrClosedPipe - return - } - // If peerWndSize is 0, we still want to send something, so don't - // block until we exceed it. - if c.cur_window() <= c.peerWndSize && len(c.unackedSends) < 64 && c.cs == csConnected { - break - } - if c.connDeadlines.write.deadlineExceeded() { - err = errTimeout - return - } - c.event.Wait() - } - var n1 int - n1, err = c.write(stData, c.send_id, p, c.seq_nr) - if err != nil { - return - } - // c.seq_nr++ - n += n1 - p = p[n1:] - } - return -} diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go b/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go deleted file mode 100644 index 622457758..000000000 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go +++ /dev/null @@ -1,411 +0,0 @@ -package utp - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "net" - "runtime" - "sync" - "testing" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" - _ "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof" -) - -func init() { - log.SetFlags(log.Flags() | log.Lshortfile) -} - -func TestUTPPingPong(t *testing.T) { - defer goroutineLeakCheck(t)() - s, err := NewSocket("udp", "localhost:0") - require.NoError(t, err) - defer s.Close() - pingerClosed := make(chan struct{}) - go func() { - defer close(pingerClosed) - b, err := Dial(s.Addr().String()) - require.NoError(t, err) - defer b.Close() - n, err := b.Write([]byte("ping")) - require.NoError(t, err) - require.EqualValues(t, 4, n) - buf := make([]byte, 4) - b.Read(buf) - require.EqualValues(t, "pong", buf) - log.Printf("got pong") - }() - a, err := s.Accept() - require.NoError(t, err) - defer a.Close() - log.Printf("accepted %s", a) - buf := make([]byte, 42) - n, err := a.Read(buf) - require.NoError(t, err) - require.EqualValues(t, "ping", buf[:n]) - log.Print("got ping") - n, err = a.Write([]byte("pong")) - require.NoError(t, err) - require.Equal(t, 4, n) - log.Print("waiting for pinger to close") - <-pingerClosed -} - -func goroutineLeakCheck(t testing.TB) func() { - if !testing.Verbose() { - return func() {} - } - numStart := runtime.NumGoroutine() - return func() { - var numNow int - for range iter.N(1) { - numNow = runtime.NumGoroutine() - if numNow == numStart { - return - } - time.Sleep(10 * time.Millisecond) - } - // I'd print stacks, or treat this as fatal, but I think - // runtime.NumGoroutine is including system routines for which we are - // not provided the stacks, and are spawned unpredictably. - t.Logf("have %d goroutines, started with %d", numNow, numStart) - } -} - -func TestDialTimeout(t *testing.T) { - defer goroutineLeakCheck(t)() - s, _ := NewSocket("udp", "localhost:0") - defer s.Close() - conn, err := DialTimeout(s.Addr().String(), 10*time.Millisecond) - if err == nil { - conn.Close() - t.Fatal("expected timeout") - } - t.Log(err) -} - -func TestMinMaxHeaderType(t *testing.T) { - require.Equal(t, stSyn, stMax) -} - -func TestUTPRawConn(t *testing.T) { - l, err := NewSocket("udp", "") - require.NoError(t, err) - defer l.Close() - go func() { - for { - _, err := l.Accept() - if err != nil { - break - } - } - }() - // Connect a UTP peer to see if the RawConn will still work. - log.Print("dialing") - utpPeer := func() net.Conn { - s, _ := NewSocket("udp", "") - defer s.Close() - ret, err := s.Dial(fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr()))) - require.NoError(t, err) - return ret - }() - log.Print("dial returned") - if err != nil { - t.Fatalf("error dialing utp listener: %s", err) - } - defer utpPeer.Close() - peer, err := net.ListenPacket("udp", ":0") - if err != nil { - t.Fatal(err) - } - defer peer.Close() - - msgsReceived := 0 - const N = 5000 // How many messages to send. - readerStopped := make(chan struct{}) - // The reader goroutine. - go func() { - defer close(readerStopped) - b := make([]byte, 500) - for i := 0; i < N; i++ { - n, _, err := l.ReadFrom(b) - if err != nil { - t.Fatalf("error reading from raw conn: %s", err) - } - msgsReceived++ - var d int - fmt.Sscan(string(b[:n]), &d) - if d != i { - log.Printf("got wrong number: expected %d, got %d", i, d) - } - } - }() - udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr()))) - if err != nil { - t.Fatal(err) - } - for i := 0; i < N; i++ { - _, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr) - if err != nil { - t.Fatal(err) - } - time.Sleep(time.Microsecond) - } - select { - case <-readerStopped: - case <-time.After(time.Second): - t.Fatal("reader timed out") - } - if msgsReceived != N { - t.Fatalf("messages received: %d", msgsReceived) - } -} - -func TestConnReadDeadline(t *testing.T) { - ls, _ := NewSocket("udp", "localhost:0") - ds, _ := NewSocket("udp", "localhost:0") - dcReadErr := make(chan error) - go func() { - c, _ := ds.Dial(ls.Addr().String()) - defer c.Close() - _, err := c.Read(nil) - dcReadErr <- err - }() - c, _ := ls.Accept() - dl := time.Now().Add(time.Millisecond) - c.SetReadDeadline(dl) - _, err := c.Read(nil) - require.Equal(t, errTimeout, err) - // The deadline has passed. - if !time.Now().After(dl) { - t.FailNow() - } - // Returns timeout on subsequent read. - _, err = c.Read(nil) - require.Equal(t, errTimeout, err) - // Disable the deadline. - c.SetReadDeadline(time.Time{}) - readReturned := make(chan struct{}) - go func() { - c.Read(nil) - close(readReturned) - }() - select { - case <-readReturned: - // Read returned but shouldn't have. - t.FailNow() - case <-time.After(time.Millisecond): - } - c.Close() - select { - case <-readReturned: - case <-time.After(time.Millisecond): - t.Fatal("read should return after Conn is closed") - } - if err := <-dcReadErr; err != io.EOF { - t.Fatalf("dial conn read returned %s", err) - } -} - -func connectSelfLots(n int, t testing.TB) { - defer goroutineLeakCheck(t)() - s, err := NewSocket("udp", "localhost:0") - if err != nil { - t.Fatal(err) - } - go func() { - for range iter.N(n) { - c, err := s.Accept() - if err != nil { - log.Fatal(err) - } - defer c.Close() - } - }() - dialErr := make(chan error) - connCh := make(chan net.Conn) - dialSema := make(chan struct{}, backlog) - for range iter.N(n) { - go func() { - dialSema <- struct{}{} - c, err := s.Dial(s.Addr().String()) - <-dialSema - if err != nil { - dialErr <- err - return - } - connCh <- c - }() - } - conns := make([]net.Conn, 0, n) - for range iter.N(n) { - select { - case c := <-connCh: - conns = append(conns, c) - case err := <-dialErr: - t.Fatal(err) - } - } - for _, c := range conns { - if c != nil { - c.Close() - } - } - s.mu.Lock() - for len(s.conns) != 0 { - // log.Print(len(s.conns)) - s.event.Wait() - } - s.mu.Unlock() - s.Close() -} - -// Connect to ourself heaps. -func TestConnectSelf(t *testing.T) { - // A rough guess says that at worst, I can only have 0x10000/3 connections - // to the same socket, due to fragmentation in the assigned connection - // IDs. - connectSelfLots(0x1000, t) -} - -func BenchmarkConnectSelf(b *testing.B) { - for range iter.N(b.N) { - connectSelfLots(2, b) - } -} - -func BenchmarkNewCloseSocket(b *testing.B) { - for range iter.N(b.N) { - s, err := NewSocket("udp", "localhost:0") - if err != nil { - b.Fatal(err) - } - err = s.Close() - if err != nil { - b.Fatal(err) - } - } -} - -func TestRejectDialBacklogFilled(t *testing.T) { - s, err := NewSocket("udp", "localhost:0") - if err != nil { - t.Fatal(err) - } - errChan := make(chan error, 1) - dial := func() { - _, err := s.Dial(s.Addr().String()) - if err != nil { - errChan <- err - } - } - // Fill the backlog. - for range iter.N(backlog + 1) { - go dial() - } - s.mu.Lock() - for len(s.backlog) < backlog { - s.event.Wait() - } - s.mu.Unlock() - select { - case <-errChan: - t.FailNow() - default: - } - // One more connection should cause a dial attempt to get reset. - go dial() - err = <-errChan - if err.Error() != "peer reset" { - t.FailNow() - } - s.Close() -} - -// Make sure that we can reset AfterFunc timers, so we don't have to create -// brand new ones everytime they fire. Specifically for the Conn resend timer. -func TestResetAfterFuncTimer(t *testing.T) { - fired := make(chan struct{}) - timer := time.AfterFunc(time.Millisecond, func() { - fired <- struct{}{} - }) - <-fired - if timer.Reset(time.Millisecond) { - // The timer should have expired - t.FailNow() - } - <-fired -} - -func connPair() (initer, accepted net.Conn) { - s, err := NewSocket("udp", "localhost:0") - if err != nil { - panic(err) - } - defer s.Close() - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - var err error - initer, err = Dial(s.Addr().String()) - if err != nil { - panic(err) - } - }() - accepted, err = s.Accept() - if err != nil { - panic(err) - } - wg.Wait() - return -} - -// Check that peer sending FIN doesn't cause unread data to be dropped in a -// receiver. -func TestReadFinishedConn(t *testing.T) { - a, b := connPair() - defer a.Close() - defer b.Close() - mu.Lock() - originalAPDC := artificialPacketDropChance - artificialPacketDropChance = 1 - mu.Unlock() - n, err := a.Write([]byte("hello")) - require.Equal(t, 5, n) - require.NoError(t, err) - n, err = a.Write([]byte("world")) - require.Equal(t, 5, n) - require.NoError(t, err) - mu.Lock() - artificialPacketDropChance = originalAPDC - mu.Unlock() - a.Close() - all, err := ioutil.ReadAll(b) - require.NoError(t, err) - require.EqualValues(t, "helloworld", all) -} - -func TestCloseDetachesQuickly(t *testing.T) { - s, _ := NewSocket("udp", "localhost:0") - defer s.Close() - go func() { - a, _ := s.Dial(s.Addr().String()) - log.Print("close a") - a.Close() - log.Print("closed a") - }() - b, _ := s.Accept() - b.Close() - s.mu.Lock() - for len(s.conns) != 0 { - log.Print(len(s.conns)) - s.event.Wait() - } - s.mu.Unlock() -} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml new file mode 100644 index 000000000..c2b5c8de0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml @@ -0,0 +1,18 @@ +language: go +sudo: false + +go: +- 1.1.2 +- 1.2.2 +- 1.3.3 +- 1.4.2 +- 1.5.1 +- tip + +matrix: + allow_failures: + - go: tip + +script: +- go vet ./... +- go test -v ./... diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE new file mode 100644 index 000000000..5515ccfb7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2013 Jeremy Saenz +All Rights Reserved. + +MIT LICENSE + +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. diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md new file mode 100644 index 000000000..364c964d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md @@ -0,0 +1,394 @@ +[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli) +[![Build Status](https://travis-ci.org/codegangsta/cli.svg?branch=master)](https://travis-ci.org/codegangsta/cli) +[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli) + +# cli.go + +`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. + +## Overview + +Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. + +**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive! + +## Installation + +Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html). + +To install `cli.go`, simply run: +``` +$ go get github.com/codegangsta/cli +``` + +Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used: +``` +export PATH=$PATH:$GOPATH/bin +``` + +## Getting Started + +One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`. + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + cli.NewApp().Run(os.Args) +} +``` + +This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Action = func(c *cli.Context) { + println("boom! I say!") + } + + app.Run(os.Args) +} +``` + +Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. + +## Example + +Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! + +Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "greet" + app.Usage = "fight the loneliness!" + app.Action = func(c *cli.Context) { + println("Hello friend!") + } + + app.Run(os.Args) +} +``` + +Install our command to the `$GOPATH/bin` directory: + +``` +$ go install +``` + +Finally run our new command: + +``` +$ greet +Hello friend! +``` + +`cli.go` also generates neat help text: + +``` +$ greet help +NAME: + greet - fight the loneliness! + +USAGE: + greet [global options] command [command options] [arguments...] + +VERSION: + 0.0.0 + +COMMANDS: + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS + --version Shows version information +``` + +### Arguments + +You can lookup arguments by calling the `Args` function on `cli.Context`. + +``` go +... +app.Action = func(c *cli.Context) { + println("Hello", c.Args()[0]) +} +... +``` + +### Flags + +Setting and querying flags is simple. + +``` go +... +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, +} +app.Action = func(c *cli.Context) { + name := "someone" + if c.NArg() > 0 { + name = c.Args()[0] + } + if c.String("lang") == "spanish" { + println("Hola", name) + } else { + println("Hello", name) + } +} +... +``` + +You can also set a destination variable for a flag, to which the content will be scanned. + +``` go +... +var language string +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + Destination: &language, + }, +} +app.Action = func(c *cli.Context) { + name := "someone" + if c.NArg() > 0 { + name = c.Args()[0] + } + if language == "spanish" { + println("Hola", name) + } else { + println("Hello", name) + } +} +... +``` + +See full list of flags at http://godoc.org/github.com/codegangsta/cli + +#### Alternate Names + +You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + }, +} +``` + +That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. + +#### Values from the Environment + +You can also have the default value set from the environment via `EnvVar`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "APP_LANG", + }, +} +``` + +The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", + }, +} +``` + +#### Values from alternate input sources (YAML and others) + +There is a separate package altsrc that adds support for getting flag values from other input sources like YAML. + +In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below: + +``` go + altsrc.NewIntFlag(cli.IntFlag{Name: "test"}) +``` + +Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below. + +``` go + command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) +``` + +The code above will use the "load" string as a flag name to get the file name of a yaml file from the cli.Context. +It will then use that file name to initialize the yaml input source for any flags that are defined on that command. +As a note the "load" flag used would also have to be defined on the command flags in order for this code snipped to work. + +Currently only YAML files are supported but developers can add support for other input sources by implementing the +altsrc.InputSourceContext for their given sources. + +Here is a more complete sample of a command using YAML support: + +``` go + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + // Action to run + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test"}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + err := command.Run(c) +``` + +### Subcommands + +Subcommands can be defined for a more git-like command line app. + +```go +... +app.Commands = []cli.Command{ + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) { + println("added task: ", c.Args().First()) + }, + }, + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + }, + { + Name: "template", + Aliases: []string{"r"}, + Usage: "options for task templates", + Subcommands: []cli.Command{ + { + Name: "add", + Usage: "add a new template", + Action: func(c *cli.Context) { + println("new task template: ", c.Args().First()) + }, + }, + { + Name: "remove", + Usage: "remove an existing template", + Action: func(c *cli.Context) { + println("removed task template: ", c.Args().First()) + }, + }, + }, + }, +} +... +``` + +### Bash Completion + +You can enable completion commands by setting the `EnableBashCompletion` +flag on the `App` object. By default, this setting will only auto-complete to +show an app's subcommands, but you can write your own completion methods for +the App or its subcommands. + +```go +... +var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} +app := cli.NewApp() +app.EnableBashCompletion = true +app.Commands = []cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + BashComplete: func(c *cli.Context) { + // This will complete if no args are passed + if c.NArg() > 0 { + return + } + for _, t := range tasks { + fmt.Println(t) + } + }, + } +} +... +``` + +#### To Enable + +Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while +setting the `PROG` variable to the name of your program: + +`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` + +#### To Distribute + +Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename +it to the name of the program you wish to add autocomplete support for (or +automatically install it there if you are distributing a package). Don't forget +to source the file to make it active in the current shell. + +``` +sudo cp src/bash_autocomplete /etc/bash_completion.d/ +source /etc/bash_completion.d/ +``` + +Alternatively, you can just document that users should source the generic +`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set +to the name of their program (as above). + +## Contribution Guidelines + +Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch. + +If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together. + +If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out. diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag.go new file mode 100644 index 000000000..f13ffb487 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag.go @@ -0,0 +1,439 @@ +package altsrc + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/codegangsta/cli" +) + +// FlagInputSourceExtension is an extension interface of cli.Flag that +// allows a value to be set on the existing parsed flags. +type FlagInputSourceExtension interface { + cli.Flag + ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error +} + +// ApplyInputSourceValues iterates over all provided flags and +// executes ApplyInputSourceValue on flags implementing the +// FlagInputSourceExtension interface to initialize these flags +// to an alternate input source. +func ApplyInputSourceValues(context *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error { + for _, f := range flags { + inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension) + if isType { + err := inputSourceExtendedFlag.ApplyInputSourceValue(context, inputSourceContext) + if err != nil { + return err + } + } + } + + return nil +} + +// InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new +// input source based on the func provided. If there is no error it will then apply the new input source to any flags +// that are supported by the input source +func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) func(context *cli.Context) error { + return func(context *cli.Context) error { + inputSource, err := createInputSource() + if err != nil { + return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error()) + } + + return ApplyInputSourceValues(context, inputSource, flags) + } +} + +// InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new +// input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is +// no error it will then apply the new input source to any flags that are supported by the input source +func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context *cli.Context) (InputSourceContext, error)) func(context *cli.Context) error { + return func(context *cli.Context) error { + inputSource, err := createInputSource(context) + if err != nil { + return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error()) + } + + return ApplyInputSourceValues(context, inputSource, flags) + } +} + +// GenericFlag is the flag type that wraps cli.GenericFlag to allow +// for other values to be specified +type GenericFlag struct { + cli.GenericFlag + set *flag.FlagSet +} + +// NewGenericFlag creates a new GenericFlag +func NewGenericFlag(flag cli.GenericFlag) *GenericFlag { + return &GenericFlag{GenericFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a generic value to the flagSet if required +func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { + value, err := isc.Generic(f.GenericFlag.Name) + if err != nil { + return err + } + if value != nil { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, value.String()) + }) + } + } + } + + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped GenericFlag.Apply +func (f *GenericFlag) Apply(set *flag.FlagSet) { + f.set = set + f.GenericFlag.Apply(set) +} + +// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow +// for other values to be specified +type StringSliceFlag struct { + cli.StringSliceFlag + set *flag.FlagSet +} + +// NewStringSliceFlag creates a new StringSliceFlag +func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag { + return &StringSliceFlag{StringSliceFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a StringSlice value to the flagSet if required +func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { + value, err := isc.StringSlice(f.StringSliceFlag.Name) + if err != nil { + return err + } + if value != nil { + var sliceValue cli.StringSlice = value + eachName(f.Name, func(name string) { + underlyingFlag := f.set.Lookup(f.Name) + if underlyingFlag != nil { + underlyingFlag.Value = &sliceValue + } + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped StringSliceFlag.Apply +func (f *StringSliceFlag) Apply(set *flag.FlagSet) { + f.set = set + f.StringSliceFlag.Apply(set) +} + +// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow +// for other values to be specified +type IntSliceFlag struct { + cli.IntSliceFlag + set *flag.FlagSet +} + +// NewIntSliceFlag creates a new IntSliceFlag +func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag { + return &IntSliceFlag{IntSliceFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a IntSlice value if required +func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { + value, err := isc.IntSlice(f.IntSliceFlag.Name) + if err != nil { + return err + } + if value != nil { + var sliceValue cli.IntSlice = value + eachName(f.Name, func(name string) { + underlyingFlag := f.set.Lookup(f.Name) + if underlyingFlag != nil { + underlyingFlag.Value = &sliceValue + } + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped IntSliceFlag.Apply +func (f *IntSliceFlag) Apply(set *flag.FlagSet) { + f.set = set + f.IntSliceFlag.Apply(set) +} + +// BoolFlag is the flag type that wraps cli.BoolFlag to allow +// for other values to be specified +type BoolFlag struct { + cli.BoolFlag + set *flag.FlagSet +} + +// NewBoolFlag creates a new BoolFlag +func NewBoolFlag(flag cli.BoolFlag) *BoolFlag { + return &BoolFlag{BoolFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a Bool value to the flagSet if required +func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { + value, err := isc.Bool(f.BoolFlag.Name) + if err != nil { + return err + } + if value { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, strconv.FormatBool(value)) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped BoolFlag.Apply +func (f *BoolFlag) Apply(set *flag.FlagSet) { + f.set = set + f.BoolFlag.Apply(set) +} + +// BoolTFlag is the flag type that wraps cli.BoolTFlag to allow +// for other values to be specified +type BoolTFlag struct { + cli.BoolTFlag + set *flag.FlagSet +} + +// NewBoolTFlag creates a new BoolTFlag +func NewBoolTFlag(flag cli.BoolTFlag) *BoolTFlag { + return &BoolTFlag{BoolTFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a BoolT value to the flagSet if required +func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { + value, err := isc.BoolT(f.BoolTFlag.Name) + if err != nil { + return err + } + if !value { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, strconv.FormatBool(value)) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped BoolTFlag.Apply +func (f *BoolTFlag) Apply(set *flag.FlagSet) { + f.set = set + + f.BoolTFlag.Apply(set) +} + +// StringFlag is the flag type that wraps cli.StringFlag to allow +// for other values to be specified +type StringFlag struct { + cli.StringFlag + set *flag.FlagSet +} + +// NewStringFlag creates a new StringFlag +func NewStringFlag(flag cli.StringFlag) *StringFlag { + return &StringFlag{StringFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a String value to the flagSet if required +func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { + value, err := isc.String(f.StringFlag.Name) + if err != nil { + return err + } + if value != "" { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, value) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped StringFlag.Apply +func (f *StringFlag) Apply(set *flag.FlagSet) { + f.set = set + + f.StringFlag.Apply(set) +} + +// IntFlag is the flag type that wraps cli.IntFlag to allow +// for other values to be specified +type IntFlag struct { + cli.IntFlag + set *flag.FlagSet +} + +// NewIntFlag creates a new IntFlag +func NewIntFlag(flag cli.IntFlag) *IntFlag { + return &IntFlag{IntFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a int value to the flagSet if required +func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { + value, err := isc.Int(f.IntFlag.Name) + if err != nil { + return err + } + if value > 0 { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, strconv.FormatInt(int64(value), 10)) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped IntFlag.Apply +func (f *IntFlag) Apply(set *flag.FlagSet) { + f.set = set + f.IntFlag.Apply(set) +} + +// DurationFlag is the flag type that wraps cli.DurationFlag to allow +// for other values to be specified +type DurationFlag struct { + cli.DurationFlag + set *flag.FlagSet +} + +// NewDurationFlag creates a new DurationFlag +func NewDurationFlag(flag cli.DurationFlag) *DurationFlag { + return &DurationFlag{DurationFlag: flag, set: nil} +} + +// ApplyInputSourceValue applies a Duration value to the flagSet if required +func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { + value, err := isc.Duration(f.DurationFlag.Name) + if err != nil { + return err + } + if value > 0 { + eachName(f.Name, func(name string) { + f.set.Set(f.Name, value.String()) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped DurationFlag.Apply +func (f *DurationFlag) Apply(set *flag.FlagSet) { + f.set = set + + f.DurationFlag.Apply(set) +} + +// Float64Flag is the flag type that wraps cli.Float64Flag to allow +// for other values to be specified +type Float64Flag struct { + cli.Float64Flag + set *flag.FlagSet +} + +// NewFloat64Flag creates a new Float64Flag +func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag { + return &Float64Flag{Float64Flag: flag, set: nil} +} + +// ApplyInputSourceValue applies a Float64 value to the flagSet if required +func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { + if f.set != nil { + if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { + value, err := isc.Float64(f.Float64Flag.Name) + if err != nil { + return err + } + if value > 0 { + floatStr := float64ToString(value) + eachName(f.Name, func(name string) { + f.set.Set(f.Name, floatStr) + }) + } + } + } + return nil +} + +// Apply saves the flagSet for later usage then calls +// the wrapped Float64Flag.Apply +func (f *Float64Flag) Apply(set *flag.FlagSet) { + f.set = set + + f.Float64Flag.Apply(set) +} + +func isEnvVarSet(envVars string) bool { + for _, envVar := range strings.Split(envVars, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + // TODO: Can't use this for bools as + // set means that it was true or false based on + // Bool flag type, should work for other types + if len(envVal) > 0 { + return true + } + } + } + + return false +} + +func float64ToString(f float64) string { + return fmt.Sprintf("%v", f) +} + +func eachName(longName string, fn func(string)) { + parts := strings.Split(longName, ",") + for _, name := range parts { + name = strings.Trim(name, " ") + fn(name) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag_test.go new file mode 100644 index 000000000..ac4d1f53a --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/flag_test.go @@ -0,0 +1,336 @@ +package altsrc + +import ( + "flag" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/codegangsta/cli" +) + +type testApplyInputSource struct { + Flag FlagInputSourceExtension + FlagName string + FlagSetName string + Expected string + ContextValueString string + ContextValue flag.Value + EnvVarValue string + EnvVarName string + MapValue interface{} +} + +func TestGenericApplyInputSourceValue(t *testing.T) { + v := &Parser{"abc", "def"} + c := runTest(t, testApplyInputSource{ + Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}), + FlagName: "test", + MapValue: v, + }) + expect(t, v, c.Generic("test")) +} + +func TestGenericApplyInputSourceMethodContextSet(t *testing.T) { + p := &Parser{"abc", "def"} + c := runTest(t, testApplyInputSource{ + Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}), + FlagName: "test", + MapValue: &Parser{"efg", "hig"}, + ContextValueString: p.String(), + }) + expect(t, p, c.Generic("test")) +} + +func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}, EnvVar: "TEST"}), + FlagName: "test", + MapValue: &Parser{"efg", "hij"}, + EnvVarName: "TEST", + EnvVarValue: "abc,def", + }) + expect(t, &Parser{"abc", "def"}, c.Generic("test")) +} + +func TestStringSliceApplyInputSourceValue(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}), + FlagName: "test", + MapValue: []string{"hello", "world"}, + }) + expect(t, c.StringSlice("test"), []string{"hello", "world"}) +} + +func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}), + FlagName: "test", + MapValue: []string{"hello", "world"}, + ContextValueString: "ohno", + }) + expect(t, c.StringSlice("test"), []string{"ohno"}) +} + +func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: []string{"hello", "world"}, + EnvVarName: "TEST", + EnvVarValue: "oh,no", + }) + expect(t, c.StringSlice("test"), []string{"oh", "no"}) +} + +func TestIntSliceApplyInputSourceValue(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}), + FlagName: "test", + MapValue: []int{1, 2}, + }) + expect(t, c.IntSlice("test"), []int{1, 2}) +} + +func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}), + FlagName: "test", + MapValue: []int{1, 2}, + ContextValueString: "3", + }) + expect(t, c.IntSlice("test"), []int{3}) +} + +func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: []int{1, 2}, + EnvVarName: "TEST", + EnvVarValue: "3,4", + }) + expect(t, c.IntSlice("test"), []int{3, 4}) +} + +func TestBoolApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}), + FlagName: "test", + MapValue: true, + }) + expect(t, true, c.Bool("test")) +} + +func TestBoolApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}), + FlagName: "test", + MapValue: false, + ContextValueString: "true", + }) + expect(t, true, c.Bool("test")) +} + +func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolFlag(cli.BoolFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: false, + EnvVarName: "TEST", + EnvVarValue: "true", + }) + expect(t, true, c.Bool("test")) +} + +func TestBoolTApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}), + FlagName: "test", + MapValue: false, + }) + expect(t, false, c.BoolT("test")) +} + +func TestBoolTApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test"}), + FlagName: "test", + MapValue: true, + ContextValueString: "false", + }) + expect(t, false, c.BoolT("test")) +} + +func TestBoolTApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewBoolTFlag(cli.BoolTFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: true, + EnvVarName: "TEST", + EnvVarValue: "false", + }) + expect(t, false, c.BoolT("test")) +} + +func TestStringApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringFlag(cli.StringFlag{Name: "test"}), + FlagName: "test", + MapValue: "hello", + }) + expect(t, "hello", c.String("test")) +} + +func TestStringApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringFlag(cli.StringFlag{Name: "test"}), + FlagName: "test", + MapValue: "hello", + ContextValueString: "goodbye", + }) + expect(t, "goodbye", c.String("test")) +} + +func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewStringFlag(cli.StringFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: "hello", + EnvVarName: "TEST", + EnvVarValue: "goodbye", + }) + expect(t, "goodbye", c.String("test")) +} + +func TestIntApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntFlag(cli.IntFlag{Name: "test"}), + FlagName: "test", + MapValue: 15, + }) + expect(t, 15, c.Int("test")) +} + +func TestIntApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntFlag(cli.IntFlag{Name: "test"}), + FlagName: "test", + MapValue: 15, + ContextValueString: "7", + }) + expect(t, 7, c.Int("test")) +} + +func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: 15, + EnvVarName: "TEST", + EnvVarValue: "12", + }) + expect(t, 12, c.Int("test")) +} + +func TestDurationApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}), + FlagName: "test", + MapValue: time.Duration(30 * time.Second), + }) + expect(t, time.Duration(30*time.Second), c.Duration("test")) +} + +func TestDurationApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}), + FlagName: "test", + MapValue: time.Duration(30 * time.Second), + ContextValueString: time.Duration(15 * time.Second).String(), + }) + expect(t, time.Duration(15*time.Second), c.Duration("test")) +} + +func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewDurationFlag(cli.DurationFlag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: time.Duration(30 * time.Second), + EnvVarName: "TEST", + EnvVarValue: time.Duration(15 * time.Second).String(), + }) + expect(t, time.Duration(15*time.Second), c.Duration("test")) +} + +func TestFloat64ApplyInputSourceMethodSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}), + FlagName: "test", + MapValue: 1.3, + }) + expect(t, 1.3, c.Float64("test")) +} + +func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}), + FlagName: "test", + MapValue: 1.3, + ContextValueString: fmt.Sprintf("%v", 1.4), + }) + expect(t, 1.4, c.Float64("test")) +} + +func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) { + c := runTest(t, testApplyInputSource{ + Flag: NewFloat64Flag(cli.Float64Flag{Name: "test", EnvVar: "TEST"}), + FlagName: "test", + MapValue: 1.3, + EnvVarName: "TEST", + EnvVarValue: fmt.Sprintf("%v", 1.4), + }) + expect(t, 1.4, c.Float64("test")) +} + +func runTest(t *testing.T, test testApplyInputSource) *cli.Context { + inputSource := &MapInputSource{valueMap: map[string]interface{}{test.FlagName: test.MapValue}} + set := flag.NewFlagSet(test.FlagSetName, flag.ContinueOnError) + c := cli.NewContext(nil, set, nil) + if test.EnvVarName != "" && test.EnvVarValue != "" { + os.Setenv(test.EnvVarName, test.EnvVarValue) + defer os.Setenv(test.EnvVarName, "") + } + + test.Flag.Apply(set) + if test.ContextValue != nil { + flag := set.Lookup(test.FlagName) + flag.Value = test.ContextValue + } + if test.ContextValueString != "" { + set.Set(test.FlagName, test.ContextValueString) + } + test.Flag.ApplyInputSourceValue(c, inputSource) + + return c +} + +type Parser [2]string + +func (p *Parser) Set(value string) error { + parts := strings.Split(value, ",") + if len(parts) != 2 { + return fmt.Errorf("invalid format") + } + + (*p)[0] = parts[0] + (*p)[1] = parts[1] + + return nil +} + +func (p *Parser) String() string { + return fmt.Sprintf("%s,%s", p[0], p[1]) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/helpers_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/helpers_test.go new file mode 100644 index 000000000..3b7f7e94e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/helpers_test.go @@ -0,0 +1,18 @@ +package altsrc + +import ( + "reflect" + "testing" +) + +func expect(t *testing.T, a interface{}, b interface{}) { + if !reflect.DeepEqual(b, a) { + t.Errorf("Expected %#v (type %v) - Got %#v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/input_source_context.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/input_source_context.go new file mode 100644 index 000000000..6d695ff16 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/input_source_context.go @@ -0,0 +1,21 @@ +package altsrc + +import ( + "time" + + "github.com/codegangsta/cli" +) + +// InputSourceContext is an interface used to allow +// other input sources to be implemented as needed. +type InputSourceContext interface { + Int(name string) (int, error) + Duration(name string) (time.Duration, error) + Float64(name string) (float64, error) + String(name string) (string, error) + StringSlice(name string) ([]string, error) + IntSlice(name string) ([]int, error) + Generic(name string) (cli.Generic, error) + Bool(name string) (bool, error) + BoolT(name string) (bool, error) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/map_input_source.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/map_input_source.go new file mode 100644 index 000000000..f1670fbc4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/map_input_source.go @@ -0,0 +1,152 @@ +package altsrc + +import ( + "fmt" + "reflect" + "time" + + "github.com/codegangsta/cli" +) + +// MapInputSource implements InputSourceContext to return +// data from the map that is loaded. +type MapInputSource struct { + valueMap map[string]interface{} +} + +// Int returns an int from the map if it exists otherwise returns 0 +func (fsm *MapInputSource) Int(name string) (int, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(int) + if !isType { + return 0, incorrectTypeForFlagError(name, "int", otherGenericValue) + } + + return otherValue, nil + } + + return 0, nil +} + +// Duration returns a duration from the map if it exists otherwise returns 0 +func (fsm *MapInputSource) Duration(name string) (time.Duration, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(time.Duration) + if !isType { + return 0, incorrectTypeForFlagError(name, "duration", otherGenericValue) + } + return otherValue, nil + } + + return 0, nil +} + +// Float64 returns an float64 from the map if it exists otherwise returns 0 +func (fsm *MapInputSource) Float64(name string) (float64, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(float64) + if !isType { + return 0, incorrectTypeForFlagError(name, "float64", otherGenericValue) + } + return otherValue, nil + } + + return 0, nil +} + +// String returns a string from the map if it exists otherwise returns an empty string +func (fsm *MapInputSource) String(name string) (string, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(string) + if !isType { + return "", incorrectTypeForFlagError(name, "string", otherGenericValue) + } + return otherValue, nil + } + + return "", nil +} + +// StringSlice returns an []string from the map if it exists otherwise returns nil +func (fsm *MapInputSource) StringSlice(name string) ([]string, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.([]string) + if !isType { + return nil, incorrectTypeForFlagError(name, "[]string", otherGenericValue) + } + return otherValue, nil + } + + return nil, nil +} + +// IntSlice returns an []int from the map if it exists otherwise returns nil +func (fsm *MapInputSource) IntSlice(name string) ([]int, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.([]int) + if !isType { + return nil, incorrectTypeForFlagError(name, "[]int", otherGenericValue) + } + return otherValue, nil + } + + return nil, nil +} + +// Generic returns an cli.Generic from the map if it exists otherwise returns nil +func (fsm *MapInputSource) Generic(name string) (cli.Generic, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(cli.Generic) + if !isType { + return nil, incorrectTypeForFlagError(name, "cli.Generic", otherGenericValue) + } + return otherValue, nil + } + + return nil, nil +} + +// Bool returns an bool from the map otherwise returns false +func (fsm *MapInputSource) Bool(name string) (bool, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(bool) + if !isType { + return false, incorrectTypeForFlagError(name, "bool", otherGenericValue) + } + return otherValue, nil + } + + return false, nil +} + +// BoolT returns an bool from the map otherwise returns true +func (fsm *MapInputSource) BoolT(name string) (bool, error) { + otherGenericValue, exists := fsm.valueMap[name] + if exists { + otherValue, isType := otherGenericValue.(bool) + if !isType { + return true, incorrectTypeForFlagError(name, "bool", otherGenericValue) + } + return otherValue, nil + } + + return true, nil +} + +func incorrectTypeForFlagError(name, expectedTypeName string, value interface{}) error { + valueType := reflect.TypeOf(value) + valueTypeName := "" + if valueType != nil { + valueTypeName = valueType.Name() + } + + return fmt.Errorf("Mismatched type for flag '%s'. Expected '%s' but actual is '%s'", name, expectedTypeName, valueTypeName) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_command_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_command_test.go new file mode 100644 index 000000000..c7ccbf7e3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_command_test.go @@ -0,0 +1,172 @@ +// Disabling building of yaml support in cases where golang is 1.0 or 1.1 +// as the encoding library is not implemented or supported. + +// +build !go1,!go1.1 + +package altsrc + +import ( + "flag" + "io/ioutil" + "os" + "testing" + + "github.com/codegangsta/cli" +) + +func TestCommandYamlFileTest(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666) + defer os.Remove("current.yaml") + test := []string{"test-cmd", "--load", "current.yaml"} + set.Parse(test) + + c := cli.NewContext(app, set, nil) + + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + val := c.Int("test") + expect(t, val, 15) + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test"}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + err := command.Run(c) + + expect(t, err, nil) +} + +func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666) + defer os.Remove("current.yaml") + + os.Setenv("THE_TEST", "10") + defer os.Setenv("THE_TEST", "") + test := []string{"test-cmd", "--load", "current.yaml"} + set.Parse(test) + + c := cli.NewContext(app, set, nil) + + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + val := c.Int("test") + expect(t, val, 10) + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + + err := command.Run(c) + + expect(t, err, nil) +} + +func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666) + defer os.Remove("current.yaml") + + test := []string{"test-cmd", "--load", "current.yaml", "--test", "7"} + set.Parse(test) + + c := cli.NewContext(app, set, nil) + + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + val := c.Int("test") + expect(t, val, 7) + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test"}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + + err := command.Run(c) + + expect(t, err, nil) +} + +func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666) + defer os.Remove("current.yaml") + + test := []string{"test-cmd", "--load", "current.yaml"} + set.Parse(test) + + c := cli.NewContext(app, set, nil) + + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + val := c.Int("test") + expect(t, val, 15) + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test", Value: 7}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + + err := command.Run(c) + + expect(t, err, nil) +} + +func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666) + defer os.Remove("current.yaml") + + os.Setenv("THE_TEST", "11") + defer os.Setenv("THE_TEST", "") + + test := []string{"test-cmd", "--load", "current.yaml"} + set.Parse(test) + + c := cli.NewContext(app, set, nil) + + command := &cli.Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(c *cli.Context) { + val := c.Int("test") + expect(t, val, 11) + }, + Flags: []cli.Flag{ + NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}), + cli.StringFlag{Name: "load"}}, + } + command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) + err := command.Run(c) + + expect(t, err, nil) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_file_loader.go b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_file_loader.go new file mode 100644 index 000000000..1251aeb43 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/altsrc/yaml_file_loader.go @@ -0,0 +1,84 @@ +// Disabling building of yaml support in cases where golang is 1.0 or 1.1 +// as the encoding library is not implemented or supported. + +// +build !go1,!go1.1 + +package altsrc + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + + "github.com/codegangsta/cli" + + "gopkg.in/yaml.v2" +) + +type yamlSourceContext struct { + FilePath string +} + +// NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath. +func NewYamlSourceFromFile(file string) (InputSourceContext, error) { + ymlLoader := &yamlSourceLoader{FilePath: file} + var results map[string]interface{} + err := readCommandYaml(ysl.FilePath, &results) + if err != nil { + return fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", filePath, err.Error()) + } + + return &MapInputSource{valueMap: results}, nil +} + +// NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a provided flag name and source context. +func NewYamlSourceFromFlagFunc(flagFileName string) func(InputSourceContext, error) { + return func(context cli.Context) { + filePath := context.String(flagFileName) + return NewYamlSourceFromFile(filePath) + } +} + +func readCommandYaml(filePath string, container interface{}) (err error) { + b, err := loadDataFrom(filePath) + if err != nil { + return err + } + + err = yaml.Unmarshal(b, container) + if err != nil { + return err + } + + err = nil + return +} + +func loadDataFrom(filePath string) ([]byte, error) { + u, err := url.Parse(filePath) + if err != nil { + return nil, err + } + + if u.Host != "" { // i have a host, now do i support the scheme? + switch u.Scheme { + case "http", "https": + res, err := http.Get(filePath) + if err != nil { + return nil, err + } + return ioutil.ReadAll(res.Body) + default: + return nil, fmt.Errorf("scheme of %s is unsupported", filePath) + } + } else if u.Path != "" { // i dont have a host, but I have a path. I am a local file. + if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil { + return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath) + } + return ioutil.ReadFile(filePath) + } else { + return nil, fmt.Errorf("unable to determine how to load from path %s", filePath) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go new file mode 100644 index 000000000..1ea3fd0b1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go @@ -0,0 +1,349 @@ +package cli + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path" + "time" +) + +// App is the main structure of a cli application. It is recommended that +// an app be created with the cli.NewApp() function +type App struct { + // The name of the program. Defaults to path.Base(os.Args[0]) + Name string + // Full name of command for help, defaults to Name + HelpName string + // Description of the program. + Usage string + // Text to override the USAGE section of help + UsageText string + // Description of the program argument format. + ArgsUsage string + // Version of the program + Version string + // List of commands to execute + Commands []Command + // List of flags to parse + Flags []Flag + // Boolean to enable bash completion commands + EnableBashCompletion bool + // Boolean to hide built-in help command + HideHelp bool + // Boolean to hide built-in version flag + HideVersion bool + // An action to execute when the bash-completion flag is set + BashComplete func(context *Context) + // An action to execute before any subcommands are run, but after the context is ready + // If a non-nil error is returned, no subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The action to execute when no subcommands are specified + Action func(context *Context) + // Execute this function if the proper command cannot be found + CommandNotFound func(context *Context, command string) + // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to replace the original error messages. + // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted. + OnUsageError func(context *Context, err error, isSubcommand bool) error + // Compilation date + Compiled time.Time + // List of all authors who contributed + Authors []Author + // Copyright of the binary if any + Copyright string + // Name of Author (Note: Use App.Authors, this is deprecated) + Author string + // Email of Author (Note: Use App.Authors, this is deprecated) + Email string + // Writer writer to write output to + Writer io.Writer +} + +// Tries to find out when this binary was compiled. +// Returns the current time if it fails to find it. +func compileTime() time.Time { + info, err := os.Stat(os.Args[0]) + if err != nil { + return time.Now() + } + return info.ModTime() +} + +// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. +func NewApp() *App { + return &App{ + Name: path.Base(os.Args[0]), + HelpName: path.Base(os.Args[0]), + Usage: "A new cli application", + UsageText: "", + Version: "0.0.0", + BashComplete: DefaultAppComplete, + Action: helpCommand.Action, + Compiled: compileTime(), + Writer: os.Stdout, + } +} + +// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination +func (a *App) Run(arguments []string) (err error) { + if a.Author != "" || a.Email != "" { + a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) + } + + newCmds := []Command{} + for _, c := range a.Commands { + if c.HelpName == "" { + c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) + } + newCmds = append(newCmds, c) + } + a.Commands = newCmds + + // append help to commands + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + + //append version/help flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + if !a.HideVersion { + a.appendFlag(VersionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(arguments[1:]) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, nil) + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + ShowAppHelp(context) + return nerr + } + + if checkCompletions(context) { + return nil + } + + if err != nil { + if a.OnUsageError != nil { + err := a.OnUsageError(context, err, false) + return err + } else { + fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.") + ShowAppHelp(context) + return err + } + } + + if !a.HideHelp && checkHelp(context) { + ShowAppHelp(context) + return nil + } + + if !a.HideVersion && checkVersion(context) { + ShowVersion(context) + return nil + } + + if a.After != nil { + defer func() { + if afterErr := a.After(context); afterErr != nil { + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if a.Before != nil { + err = a.Before(context) + if err != nil { + fmt.Fprintf(a.Writer, "%v\n\n", err) + ShowAppHelp(context) + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + return nil +} + +// Another entry point to the cli app, takes care of passing arguments and error handling +func (a *App) RunAndExitOnError() { + if err := a.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags +func (a *App) RunAsSubcommand(ctx *Context) (err error) { + // append help to commands + if len(a.Commands) > 0 { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + } + + newCmds := []Command{} + for _, c := range a.Commands { + if c.HelpName == "" { + c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) + } + newCmds = append(newCmds, c) + } + a.Commands = newCmds + + // append flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(ctx.Args().Tail()) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, ctx) + + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + fmt.Fprintln(a.Writer) + if len(a.Commands) > 0 { + ShowSubcommandHelp(context) + } else { + ShowCommandHelp(ctx, context.Args().First()) + } + return nerr + } + + if checkCompletions(context) { + return nil + } + + if err != nil { + if a.OnUsageError != nil { + err = a.OnUsageError(context, err, true) + return err + } else { + fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.") + ShowSubcommandHelp(context) + return err + } + } + + if len(a.Commands) > 0 { + if checkSubcommandHelp(context) { + return nil + } + } else { + if checkCommandHelp(ctx, context.Args().First()) { + return nil + } + } + + if a.After != nil { + defer func() { + afterErr := a.After(context) + if afterErr != nil { + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if a.Before != nil { + err := a.Before(context) + if err != nil { + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + + return nil +} + +// Returns the named command on App. Returns nil if the command does not exist +func (a *App) Command(name string) *Command { + for _, c := range a.Commands { + if c.HasName(name) { + return &c + } + } + + return nil +} + +func (a *App) hasFlag(flag Flag) bool { + for _, f := range a.Flags { + if flag == f { + return true + } + } + + return false +} + +func (a *App) appendFlag(flag Flag) { + if !a.hasFlag(flag) { + a.Flags = append(a.Flags, flag) + } +} + +// Author represents someone who has contributed to a cli project. +type Author struct { + Name string // The Authors name + Email string // The Authors email +} + +// String makes Author comply to the Stringer interface, to allow an easy print in the templating process +func (a Author) String() string { + e := "" + if a.Email != "" { + e = "<" + a.Email + "> " + } + + return fmt.Sprintf("%v %v", a.Name, e) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go new file mode 100644 index 000000000..7feaf1f52 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go @@ -0,0 +1,1047 @@ +package cli + +import ( + "bytes" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "testing" +) + +func ExampleApp_Run() { + // set args for examples sake + os.Args = []string{"greet", "--name", "Jeremy"} + + app := NewApp() + app.Name = "greet" + app.Flags = []Flag{ + StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Action = func(c *Context) { + fmt.Printf("Hello %v\n", c.String("name")) + } + app.UsageText = "app [first_arg] [second_arg]" + app.Author = "Harrison" + app.Email = "harrison@lolwut.com" + app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}} + app.Run(os.Args) + // Output: + // Hello Jeremy +} + +func ExampleApp_Run_subcommand() { + // set args for examples sake + os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} + app := NewApp() + app.Name = "say" + app.Commands = []Command{ + { + Name: "hello", + Aliases: []string{"hi"}, + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []Command{ + { + Name: "english", + Aliases: []string{"en"}, + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []Flag{ + StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *Context) { + fmt.Println("Hello,", c.String("name")) + }, + }, + }, + }, + } + + app.Run(os.Args) + // Output: + // Hello, Jeremy +} + +func ExampleApp_Run_help() { + // set args for examples sake + os.Args = []string{"greet", "h", "describeit"} + + app := NewApp() + app.Name = "greet" + app.Flags = []Flag{ + StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Commands = []Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *Context) { + fmt.Printf("i like to describe things") + }, + }, + } + app.Run(os.Args) + // Output: + // NAME: + // greet describeit - use it to see a description + // + // USAGE: + // greet describeit [arguments...] + // + // DESCRIPTION: + // This is how we describe describeit the function +} + +func ExampleApp_Run_bashComplete() { + // set args for examples sake + os.Args = []string{"greet", "--generate-bash-completion"} + + app := NewApp() + app.Name = "greet" + app.EnableBashCompletion = true + app.Commands = []Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *Context) { + fmt.Printf("i like to describe things") + }, + }, { + Name: "next", + Usage: "next example", + Description: "more stuff to see when generating bash completion", + Action: func(c *Context) { + fmt.Printf("the next example") + }, + }, + } + + app.Run(os.Args) + // Output: + // describeit + // d + // next + // help + // h +} + +func TestApp_Run(t *testing.T) { + s := "" + + app := NewApp() + app.Action = func(c *Context) { + s = s + c.Args().First() + } + + err := app.Run([]string{"command", "foo"}) + expect(t, err, nil) + err = app.Run([]string{"command", "bar"}) + expect(t, err, nil) + expect(t, s, "foobar") +} + +var commandAppTests = []struct { + name string + expected bool +}{ + {"foobar", true}, + {"batbaz", true}, + {"b", true}, + {"f", true}, + {"bat", false}, + {"nothing", false}, +} + +func TestApp_Command(t *testing.T) { + app := NewApp() + fooCommand := Command{Name: "foobar", Aliases: []string{"f"}} + batCommand := Command{Name: "batbaz", Aliases: []string{"b"}} + app.Commands = []Command{ + fooCommand, + batCommand, + } + + for _, test := range commandAppTests { + expect(t, app.Command(test.name) != nil, test.expected) + } +} + +func TestApp_CommandWithArgBeforeFlags(t *testing.T) { + var parsedOption, firstArg string + + app := NewApp() + command := Command{ + Name: "cmd", + Flags: []Flag{ + StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *Context) { + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) + + expect(t, parsedOption, "my-option") + expect(t, firstArg, "my-arg") +} + +func TestApp_RunAsSubcommandParseFlags(t *testing.T) { + var context *Context + + a := NewApp() + a.Commands = []Command{ + { + Name: "foo", + Action: func(c *Context) { + context = c + }, + Flags: []Flag{ + StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, + }, + Before: func(_ *Context) error { return nil }, + }, + } + a.Run([]string{"", "foo", "--lang", "spanish", "abcd"}) + + expect(t, context.Args().Get(0), "abcd") + expect(t, context.String("lang"), "spanish") +} + +func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { + var parsedOption string + var args []string + + app := NewApp() + command := Command{ + Name: "cmd", + Flags: []Flag{ + StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *Context) { + parsedOption = c.String("option") + args = c.Args() + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"}) + + expect(t, parsedOption, "my-option") + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "--notARealFlag") +} + +func TestApp_CommandWithDash(t *testing.T) { + var args []string + + app := NewApp() + command := Command{ + Name: "cmd", + Action: func(c *Context) { + args = c.Args() + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "-"}) + + expect(t, args[0], "my-arg") + expect(t, args[1], "-") +} + +func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { + var args []string + + app := NewApp() + command := Command{ + Name: "cmd", + Action: func(c *Context) { + args = c.Args() + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) + + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "notAFlagAtAll") +} + +func TestApp_Float64Flag(t *testing.T) { + var meters float64 + + app := NewApp() + app.Flags = []Flag{ + Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, + } + app.Action = func(c *Context) { + meters = c.Float64("height") + } + + app.Run([]string{"", "--height", "1.93"}) + expect(t, meters, 1.93) +} + +func TestApp_ParseSliceFlags(t *testing.T) { + var parsedOption, firstArg string + var parsedIntSlice []int + var parsedStringSlice []string + + app := NewApp() + command := Command{ + Name: "cmd", + Flags: []Flag{ + IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"}, + StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"}, + }, + Action: func(c *Context) { + parsedIntSlice = c.IntSlice("p") + parsedStringSlice = c.StringSlice("ip") + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}) + + IntsEquals := func(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + + StrsEquals := func(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + var expectedIntSlice = []int{22, 80} + var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} + + if !IntsEquals(parsedIntSlice, expectedIntSlice) { + t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) + } + + if !StrsEquals(parsedStringSlice, expectedStringSlice) { + t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) + } +} + +func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) { + var parsedIntSlice []int + var parsedStringSlice []string + + app := NewApp() + command := Command{ + Name: "cmd", + Flags: []Flag{ + IntSliceFlag{Name: "a", Usage: "set numbers"}, + StringSliceFlag{Name: "str", Usage: "set strings"}, + }, + Action: func(c *Context) { + parsedIntSlice = c.IntSlice("a") + parsedStringSlice = c.StringSlice("str") + }, + } + app.Commands = []Command{command} + + app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"}) + + var expectedIntSlice = []int{2} + var expectedStringSlice = []string{"A"} + + if parsedIntSlice[0] != expectedIntSlice[0] { + t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0]) + } + + if parsedStringSlice[0] != expectedStringSlice[0] { + t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0]) + } +} + +func TestApp_DefaultStdout(t *testing.T) { + app := NewApp() + + if app.Writer != os.Stdout { + t.Error("Default output writer not set.") + } +} + +type mockWriter struct { + written []byte +} + +func (fw *mockWriter) Write(p []byte) (n int, err error) { + if fw.written == nil { + fw.written = p + } else { + fw.written = append(fw.written, p...) + } + + return len(p), nil +} + +func (fw *mockWriter) GetWritten() (b []byte) { + return fw.written +} + +func TestApp_SetStdout(t *testing.T) { + w := &mockWriter{} + + app := NewApp() + app.Name = "test" + app.Writer = w + + err := app.Run([]string{"help"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if len(w.written) == 0 { + t.Error("App did not write output to desired writer.") + } +} + +func TestApp_BeforeFunc(t *testing.T) { + beforeRun, subcommandRun := false, false + beforeError := fmt.Errorf("fail") + var err error + + app := NewApp() + + app.Before = func(c *Context) error { + beforeRun = true + s := c.String("opt") + if s == "fail" { + return beforeError + } + + return nil + } + + app.Commands = []Command{ + Command{ + Name: "sub", + Action: func(c *Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []Flag{ + StringFlag{Name: "opt"}, + } + + // run with the Before() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + beforeRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != beforeError { + t.Errorf("Run error expected, but not received") + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == true { + t.Errorf("Subcommand executed when NOT expected") + } + +} + +func TestApp_AfterFunc(t *testing.T) { + afterRun, subcommandRun := false, false + afterError := fmt.Errorf("fail") + var err error + + app := NewApp() + + app.After = func(c *Context) error { + afterRun = true + s := c.String("opt") + if s == "fail" { + return afterError + } + + return nil + } + + app.Commands = []Command{ + Command{ + Name: "sub", + Action: func(c *Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []Flag{ + StringFlag{Name: "opt"}, + } + + // run with the After() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + afterRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != afterError { + t.Errorf("Run error expected, but not received") + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } +} + +func TestAppNoHelpFlag(t *testing.T) { + oldFlag := HelpFlag + defer func() { + HelpFlag = oldFlag + }() + + HelpFlag = BoolFlag{} + + app := NewApp() + app.Writer = ioutil.Discard + err := app.Run([]string{"test", "-h"}) + + if err != flag.ErrHelp { + t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err) + } +} + +func TestAppHelpPrinter(t *testing.T) { + oldPrinter := HelpPrinter + defer func() { + HelpPrinter = oldPrinter + }() + + var wasCalled = false + HelpPrinter = func(w io.Writer, template string, data interface{}) { + wasCalled = true + } + + app := NewApp() + app.Run([]string{"-h"}) + + if wasCalled == false { + t.Errorf("Help printer expected to be called, but was not") + } +} + +func TestAppVersionPrinter(t *testing.T) { + oldPrinter := VersionPrinter + defer func() { + VersionPrinter = oldPrinter + }() + + var wasCalled = false + VersionPrinter = func(c *Context) { + wasCalled = true + } + + app := NewApp() + ctx := NewContext(app, nil, nil) + ShowVersion(ctx) + + if wasCalled == false { + t.Errorf("Version printer expected to be called, but was not") + } +} + +func TestAppCommandNotFound(t *testing.T) { + beforeRun, subcommandRun := false, false + app := NewApp() + + app.CommandNotFound = func(c *Context, command string) { + beforeRun = true + } + + app.Commands = []Command{ + Command{ + Name: "bar", + Action: func(c *Context) { + subcommandRun = true + }, + }, + } + + app.Run([]string{"command", "foo"}) + + expect(t, beforeRun, true) + expect(t, subcommandRun, false) +} + +func TestGlobalFlag(t *testing.T) { + var globalFlag string + var globalFlagSet bool + app := NewApp() + app.Flags = []Flag{ + StringFlag{Name: "global, g", Usage: "global"}, + } + app.Action = func(c *Context) { + globalFlag = c.GlobalString("global") + globalFlagSet = c.GlobalIsSet("global") + } + app.Run([]string{"command", "-g", "foo"}) + expect(t, globalFlag, "foo") + expect(t, globalFlagSet, true) + +} + +func TestGlobalFlagsInSubcommands(t *testing.T) { + subcommandRun := false + parentFlag := false + app := NewApp() + + app.Flags = []Flag{ + BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, + } + + app.Commands = []Command{ + Command{ + Name: "foo", + Flags: []Flag{ + BoolFlag{Name: "parent, p", Usage: "Parent flag"}, + }, + Subcommands: []Command{ + { + Name: "bar", + Action: func(c *Context) { + if c.GlobalBool("debug") { + subcommandRun = true + } + if c.GlobalBool("parent") { + parentFlag = true + } + }, + }, + }, + }, + } + + app.Run([]string{"command", "-d", "foo", "-p", "bar"}) + + expect(t, subcommandRun, true) + expect(t, parentFlag, true) +} + +func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) { + var subcommandHelpTopics = [][]string{ + {"command", "foo", "--help"}, + {"command", "foo", "-h"}, + {"command", "foo", "help"}, + } + + for _, flagSet := range subcommandHelpTopics { + t.Logf("==> checking with flags %v", flagSet) + + app := NewApp() + buf := new(bytes.Buffer) + app.Writer = buf + + subCmdBar := Command{ + Name: "bar", + Usage: "does bar things", + } + subCmdBaz := Command{ + Name: "baz", + Usage: "does baz things", + } + cmd := Command{ + Name: "foo", + Description: "descriptive wall of text about how it does foo things", + Subcommands: []Command{subCmdBar, subCmdBaz}, + } + + app.Commands = []Command{cmd} + err := app.Run(flagSet) + + if err != nil { + t.Error(err) + } + + output := buf.String() + t.Logf("output: %q\n", buf.Bytes()) + + if strings.Contains(output, "No help topic for") { + t.Errorf("expect a help topic, got none: \n%q", output) + } + + for _, shouldContain := range []string{ + cmd.Name, cmd.Description, + subCmdBar.Name, subCmdBar.Usage, + subCmdBaz.Name, subCmdBaz.Usage, + } { + if !strings.Contains(output, shouldContain) { + t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output) + } + } + } +} + +func TestApp_Run_SubcommandFullPath(t *testing.T) { + app := NewApp() + buf := new(bytes.Buffer) + app.Writer = buf + app.Name = "command" + subCmd := Command{ + Name: "bar", + Usage: "does bar things", + } + cmd := Command{ + Name: "foo", + Description: "foo commands", + Subcommands: []Command{subCmd}, + } + app.Commands = []Command{cmd} + + err := app.Run([]string{"command", "foo", "bar", "--help"}) + if err != nil { + t.Error(err) + } + + output := buf.String() + if !strings.Contains(output, "command foo bar - does bar things") { + t.Errorf("expected full path to subcommand: %s", output) + } + if !strings.Contains(output, "command foo bar [arguments...]") { + t.Errorf("expected full path to subcommand: %s", output) + } +} + +func TestApp_Run_SubcommandHelpName(t *testing.T) { + app := NewApp() + buf := new(bytes.Buffer) + app.Writer = buf + app.Name = "command" + subCmd := Command{ + Name: "bar", + HelpName: "custom", + Usage: "does bar things", + } + cmd := Command{ + Name: "foo", + Description: "foo commands", + Subcommands: []Command{subCmd}, + } + app.Commands = []Command{cmd} + + err := app.Run([]string{"command", "foo", "bar", "--help"}) + if err != nil { + t.Error(err) + } + + output := buf.String() + if !strings.Contains(output, "custom - does bar things") { + t.Errorf("expected HelpName for subcommand: %s", output) + } + if !strings.Contains(output, "custom [arguments...]") { + t.Errorf("expected HelpName to subcommand: %s", output) + } +} + +func TestApp_Run_CommandHelpName(t *testing.T) { + app := NewApp() + buf := new(bytes.Buffer) + app.Writer = buf + app.Name = "command" + subCmd := Command{ + Name: "bar", + Usage: "does bar things", + } + cmd := Command{ + Name: "foo", + HelpName: "custom", + Description: "foo commands", + Subcommands: []Command{subCmd}, + } + app.Commands = []Command{cmd} + + err := app.Run([]string{"command", "foo", "bar", "--help"}) + if err != nil { + t.Error(err) + } + + output := buf.String() + if !strings.Contains(output, "command foo bar - does bar things") { + t.Errorf("expected full path to subcommand: %s", output) + } + if !strings.Contains(output, "command foo bar [arguments...]") { + t.Errorf("expected full path to subcommand: %s", output) + } +} + +func TestApp_Run_CommandSubcommandHelpName(t *testing.T) { + app := NewApp() + buf := new(bytes.Buffer) + app.Writer = buf + app.Name = "base" + subCmd := Command{ + Name: "bar", + HelpName: "custom", + Usage: "does bar things", + } + cmd := Command{ + Name: "foo", + Description: "foo commands", + Subcommands: []Command{subCmd}, + } + app.Commands = []Command{cmd} + + err := app.Run([]string{"command", "foo", "--help"}) + if err != nil { + t.Error(err) + } + + output := buf.String() + if !strings.Contains(output, "base foo - foo commands") { + t.Errorf("expected full path to subcommand: %s", output) + } + if !strings.Contains(output, "base foo command [command options] [arguments...]") { + t.Errorf("expected full path to subcommand: %s", output) + } +} + +func TestApp_Run_Help(t *testing.T) { + var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}} + + for _, args := range helpArguments { + buf := new(bytes.Buffer) + + t.Logf("==> checking with arguments %v", args) + + app := NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Writer = buf + app.Action = func(c *Context) { + buf.WriteString("boom I say!") + } + + err := app.Run(args) + if err != nil { + t.Error(err) + } + + output := buf.String() + t.Logf("output: %q\n", buf.Bytes()) + + if !strings.Contains(output, "boom - make an explosive entrance") { + t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output) + } + } +} + +func TestApp_Run_Version(t *testing.T) { + var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}} + + for _, args := range versionArguments { + buf := new(bytes.Buffer) + + t.Logf("==> checking with arguments %v", args) + + app := NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Version = "0.1.0" + app.Writer = buf + app.Action = func(c *Context) { + buf.WriteString("boom I say!") + } + + err := app.Run(args) + if err != nil { + t.Error(err) + } + + output := buf.String() + t.Logf("output: %q\n", buf.Bytes()) + + if !strings.Contains(output, "0.1.0") { + t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output) + } + } +} + +func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { + app := NewApp() + app.Action = func(c *Context) {} + app.Before = func(c *Context) error { return fmt.Errorf("before error") } + app.After = func(c *Context) error { return fmt.Errorf("after error") } + + err := app.Run([]string{"foo"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.Contains(err.Error(), "before error") { + t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) + } + if !strings.Contains(err.Error(), "after error") { + t.Errorf("expected text of error from After method, but got none in \"%v\"", err) + } +} + +func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { + app := NewApp() + app.Commands = []Command{ + Command{ + Subcommands: []Command{ + Command{ + Name: "sub", + }, + }, + Name: "bar", + Before: func(c *Context) error { return fmt.Errorf("before error") }, + After: func(c *Context) error { return fmt.Errorf("after error") }, + }, + } + + err := app.Run([]string{"foo", "bar"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.Contains(err.Error(), "before error") { + t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) + } + if !strings.Contains(err.Error(), "after error") { + t.Errorf("expected text of error from After method, but got none in \"%v\"", err) + } +} + +func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { + app := NewApp() + app.Flags = []Flag{ + IntFlag{Name: "flag"}, + } + app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect no subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + } + app.Commands = []Command{ + Command{ + Name: "bar", + }, + } + + err := app.Run([]string{"foo", "--flag=wrong"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} + +func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) { + app := NewApp() + app.Flags = []Flag{ + IntFlag{Name: "flag"}, + } + app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + } + app.Commands = []Command{ + Command{ + Name: "bar", + }, + } + + err := app.Run([]string{"foo", "--flag=wrong", "bar"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml new file mode 100644 index 000000000..3ca7afabd --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml @@ -0,0 +1,16 @@ +version: "{build}" + +os: Windows Server 2012 R2 + +install: + - go version + - go env + +build_script: + - cd %APPVEYOR_BUILD_FOLDER% + - go vet ./... + - go test -v ./... + +test: off + +deploy: off diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete new file mode 100644 index 000000000..21a232f1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete @@ -0,0 +1,14 @@ +#! /bin/bash + +: ${PROG:=$(basename ${BASH_SOURCE})} + +_cli_bash_autocomplete() { + local cur opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + } + + complete -F _cli_bash_autocomplete $PROG diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete new file mode 100644 index 000000000..5430a18f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete @@ -0,0 +1,5 @@ +autoload -U compinit && compinit +autoload -U bashcompinit && bashcompinit + +script_dir=$(dirname $0) +source ${script_dir}/bash_autocomplete diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go new file mode 100644 index 000000000..31dc9124d --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go @@ -0,0 +1,40 @@ +// Package cli provides a minimal framework for creating and organizing command line +// Go applications. cli is designed to be easy to understand and write, the most simple +// cli application can be written as follows: +// func main() { +// cli.NewApp().Run(os.Args) +// } +// +// Of course this application does not do much, so let's make this an actual application: +// func main() { +// app := cli.NewApp() +// app.Name = "greet" +// app.Usage = "say a greeting" +// app.Action = func(c *cli.Context) { +// println("Greetings") +// } +// +// app.Run(os.Args) +// } +package cli + +import ( + "strings" +) + +type MultiError struct { + Errors []error +} + +func NewMultiError(err ...error) MultiError { + return MultiError{Errors: err} +} + +func (m MultiError) Error() string { + errs := make([]string, len(m.Errors)) + for i, err := range m.Errors { + errs[i] = err.Error() + } + + return strings.Join(errs, "\n") +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go new file mode 100644 index 000000000..01537132f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go @@ -0,0 +1,250 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "strings" +) + +// Command is a subcommand for a cli.App. +type Command struct { + // The name of the command + Name string + // short name of the command. Typically one character (deprecated, use `Aliases`) + ShortName string + // A list of aliases for the command + Aliases []string + // A short description of the usage of this command + Usage string + // Custom text to show on USAGE section of help + UsageText string + // A longer explanation of how the command works + Description string + // A short description of the arguments of this command + ArgsUsage string + // The function to call when checking for bash command completions + BashComplete func(context *Context) + // An action to execute before any sub-subcommands are run, but after the context is ready + // If a non-nil error is returned, no sub-subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but before the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The function to call when this command is invoked + Action func(context *Context) + // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages. + // This function is able to replace the original error messages. + // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted. + OnUsageError func(context *Context, err error) error + // List of child commands + Subcommands []Command + // List of flags to parse + Flags []Flag + // Treat all flags as normal arguments if true + SkipFlagParsing bool + // Boolean to hide built-in help command + HideHelp bool + + // Full name of command for help, defaults to full command name, including parent commands. + HelpName string + commandNamePath []string +} + +// Returns the full name of the command. +// For subcommands this ensures that parent commands are part of the command path +func (c Command) FullName() string { + if c.commandNamePath == nil { + return c.Name + } + return strings.Join(c.commandNamePath, " ") +} + +// Invokes the command given the context, parses ctx.Args() to generate command-specific flags +func (c Command) Run(ctx *Context) (err error) { + if len(c.Subcommands) > 0 { + return c.startApp(ctx) + } + + if !c.HideHelp && (HelpFlag != BoolFlag{}) { + // append help to flags + c.Flags = append( + c.Flags, + HelpFlag, + ) + } + + if ctx.App.EnableBashCompletion { + c.Flags = append(c.Flags, BashCompletionFlag) + } + + set := flagSet(c.Name, c.Flags) + set.SetOutput(ioutil.Discard) + + if !c.SkipFlagParsing { + firstFlagIndex := -1 + terminatorIndex := -1 + for index, arg := range ctx.Args() { + if arg == "--" { + terminatorIndex = index + break + } else if arg == "-" { + // Do nothing. A dash alone is not really a flag. + continue + } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { + firstFlagIndex = index + } + } + + if firstFlagIndex > -1 { + args := ctx.Args() + regularArgs := make([]string, len(args[1:firstFlagIndex])) + copy(regularArgs, args[1:firstFlagIndex]) + + var flagArgs []string + if terminatorIndex > -1 { + flagArgs = args[firstFlagIndex:terminatorIndex] + regularArgs = append(regularArgs, args[terminatorIndex:]...) + } else { + flagArgs = args[firstFlagIndex:] + } + + err = set.Parse(append(flagArgs, regularArgs...)) + } else { + err = set.Parse(ctx.Args().Tail()) + } + } else { + if c.SkipFlagParsing { + err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) + } + } + + if err != nil { + if c.OnUsageError != nil { + err := c.OnUsageError(ctx, err) + return err + } else { + fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return err + } + } + + nerr := normalizeFlags(c.Flags, set) + if nerr != nil { + fmt.Fprintln(ctx.App.Writer, nerr) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return nerr + } + context := NewContext(ctx.App, set, ctx) + + if checkCommandCompletions(context, c.Name) { + return nil + } + + if checkCommandHelp(context, c.Name) { + return nil + } + + if c.After != nil { + defer func() { + afterErr := c.After(context) + if afterErr != nil { + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if c.Before != nil { + err := c.Before(context) + if err != nil { + fmt.Fprintln(ctx.App.Writer, err) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return err + } + } + + context.Command = c + c.Action(context) + return nil +} + +func (c Command) Names() []string { + names := []string{c.Name} + + if c.ShortName != "" { + names = append(names, c.ShortName) + } + + return append(names, c.Aliases...) +} + +// Returns true if Command.Name or Command.ShortName matches given name +func (c Command) HasName(name string) bool { + for _, n := range c.Names() { + if n == name { + return true + } + } + return false +} + +func (c Command) startApp(ctx *Context) error { + app := NewApp() + + // set the name and usage + app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) + if c.HelpName == "" { + app.HelpName = c.HelpName + } else { + app.HelpName = app.Name + } + + if c.Description != "" { + app.Usage = c.Description + } else { + app.Usage = c.Usage + } + + // set CommandNotFound + app.CommandNotFound = ctx.App.CommandNotFound + + // set the flags and commands + app.Commands = c.Subcommands + app.Flags = c.Flags + app.HideHelp = c.HideHelp + + app.Version = ctx.App.Version + app.HideVersion = ctx.App.HideVersion + app.Compiled = ctx.App.Compiled + app.Author = ctx.App.Author + app.Email = ctx.App.Email + app.Writer = ctx.App.Writer + + // bash completion + app.EnableBashCompletion = ctx.App.EnableBashCompletion + if c.BashComplete != nil { + app.BashComplete = c.BashComplete + } + + // set the actions + app.Before = c.Before + app.After = c.After + if c.Action != nil { + app.Action = c.Action + } else { + app.Action = helpSubcommand.Action + } + + for index, cc := range app.Commands { + app.Commands[index].commandNamePath = []string{c.Name, cc.Name} + } + + return app.RunAsSubcommand(ctx) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go new file mode 100644 index 000000000..827da1df2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go @@ -0,0 +1,97 @@ +package cli + +import ( + "errors" + "flag" + "fmt" + "io/ioutil" + "strings" + "testing" +) + +func TestCommandFlagParsing(t *testing.T) { + cases := []struct { + testArgs []string + skipFlagParsing bool + expectedErr error + }{ + {[]string{"blah", "blah", "-break"}, false, errors.New("flag provided but not defined: -break")}, // Test normal "not ignoring flags" flow + {[]string{"blah", "blah"}, true, nil}, // Test SkipFlagParsing without any args that look like flags + {[]string{"blah", "-break"}, true, nil}, // Test SkipFlagParsing with random flag arg + {[]string{"blah", "-help"}, true, nil}, // Test SkipFlagParsing with "special" help flag arg + } + + for _, c := range cases { + app := NewApp() + app.Writer = ioutil.Discard + set := flag.NewFlagSet("test", 0) + set.Parse(c.testArgs) + + context := NewContext(app, set, nil) + + command := Command{ + Name: "test-cmd", + Aliases: []string{"tc"}, + Usage: "this is for testing", + Description: "testing", + Action: func(_ *Context) {}, + } + + command.SkipFlagParsing = c.skipFlagParsing + + err := command.Run(context) + + expect(t, err, c.expectedErr) + expect(t, []string(context.Args()), c.testArgs) + } +} + +func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { + app := NewApp() + app.Commands = []Command{ + Command{ + Name: "bar", + Before: func(c *Context) error { return fmt.Errorf("before error") }, + After: func(c *Context) error { return fmt.Errorf("after error") }, + }, + } + + err := app.Run([]string{"foo", "bar"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.Contains(err.Error(), "before error") { + t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) + } + if !strings.Contains(err.Error(), "after error") { + t.Errorf("expected text of error from After method, but got none in \"%v\"", err) + } +} + +func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { + app := NewApp() + app.Commands = []Command{ + Command{ + Name: "bar", + Flags: []Flag{ + IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error) error { + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + }, + }, + } + + err := app.Run([]string{"foo", "bar", "--flag=wrong"}) + if err == nil { + t.Fatalf("expected to receive error from Run, got none") + } + + if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { + t.Errorf("Expect an intercepted error, but got \"%v\"", err) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go new file mode 100644 index 000000000..b66d278d0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go @@ -0,0 +1,393 @@ +package cli + +import ( + "errors" + "flag" + "strconv" + "strings" + "time" +) + +// Context is a type that is passed through to +// each Handler action in a cli application. Context +// can be used to retrieve context-specific Args and +// parsed command-line options. +type Context struct { + App *App + Command Command + flagSet *flag.FlagSet + setFlags map[string]bool + globalSetFlags map[string]bool + parentContext *Context +} + +// Creates a new context. For use in when invoking an App or Command action. +func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { + return &Context{App: app, flagSet: set, parentContext: parentCtx} +} + +// Looks up the value of a local int flag, returns 0 if no int flag exists +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// Looks up the value of a local bool flag, returns false if no bool flag exists +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// Looks up the value of a local boolT flag, returns false if no bool flag exists +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// Looks up the value of a local string flag, returns "" if no string flag exists +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// Looks up the value of a local string slice flag, returns nil if no string slice flag exists +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// Looks up the value of a local int slice flag, returns nil if no int slice flag exists +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// Looks up the value of a local generic flag, returns nil if no generic flag exists +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// Looks up the value of a global int flag, returns 0 if no int flag exists +func (c *Context) GlobalInt(name string) int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt(name, fs) + } + return 0 +} + +// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) GlobalDuration(name string) time.Duration { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupDuration(name, fs) + } + return 0 +} + +// Looks up the value of a global bool flag, returns false if no bool flag exists +func (c *Context) GlobalBool(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBool(name, fs) + } + return false +} + +// Looks up the value of a global string flag, returns "" if no string flag exists +func (c *Context) GlobalString(name string) string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupString(name, fs) + } + return "" +} + +// Looks up the value of a global string slice flag, returns nil if no string slice flag exists +func (c *Context) GlobalStringSlice(name string) []string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupStringSlice(name, fs) + } + return nil +} + +// Looks up the value of a global int slice flag, returns nil if no int slice flag exists +func (c *Context) GlobalIntSlice(name string) []int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupIntSlice(name, fs) + } + return nil +} + +// Looks up the value of a global generic flag, returns nil if no generic flag exists +func (c *Context) GlobalGeneric(name string) interface{} { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupGeneric(name, fs) + } + return nil +} + +// Returns the number of flags set +func (c *Context) NumFlags() int { + return c.flagSet.NFlag() +} + +// Determines if the flag was actually set +func (c *Context) IsSet(name string) bool { + if c.setFlags == nil { + c.setFlags = make(map[string]bool) + c.flagSet.Visit(func(f *flag.Flag) { + c.setFlags[f.Name] = true + }) + } + return c.setFlags[name] == true +} + +// Determines if the global flag was actually set +func (c *Context) GlobalIsSet(name string) bool { + if c.globalSetFlags == nil { + c.globalSetFlags = make(map[string]bool) + ctx := c + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { + ctx.flagSet.Visit(func(f *flag.Flag) { + c.globalSetFlags[f.Name] = true + }) + } + } + return c.globalSetFlags[name] +} + +// Returns a slice of flag names used in this context. +func (c *Context) FlagNames() (names []string) { + for _, flag := range c.Command.Flags { + name := strings.Split(flag.GetName(), ",")[0] + if name == "help" { + continue + } + names = append(names, name) + } + return +} + +// Returns a slice of global flag names used by the app. +func (c *Context) GlobalFlagNames() (names []string) { + for _, flag := range c.App.Flags { + name := strings.Split(flag.GetName(), ",")[0] + if name == "help" || name == "version" { + continue + } + names = append(names, name) + } + return +} + +// Returns the parent context, if any +func (c *Context) Parent() *Context { + return c.parentContext +} + +type Args []string + +// Returns the command line arguments associated with the context. +func (c *Context) Args() Args { + args := Args(c.flagSet.Args()) + return args +} + +// Returns the number of the command line arguments. +func (c *Context) NArg() int { + return len(c.Args()) +} + +// Returns the nth argument, or else a blank string +func (a Args) Get(n int) string { + if len(a) > n { + return a[n] + } + return "" +} + +// Returns the first argument, or else a blank string +func (a Args) First() string { + return a.Get(0) +} + +// Return the rest of the arguments (not the first one) +// or else an empty string slice +func (a Args) Tail() []string { + if len(a) >= 2 { + return []string(a)[1:] + } + return []string{} +} + +// Checks if there are any arguments present +func (a Args) Present() bool { + return len(a) != 0 +} + +// Swaps arguments at the given indexes +func (a Args) Swap(from, to int) error { + if from >= len(a) || to >= len(a) { + return errors.New("index out of range") + } + a[from], a[to] = a[to], a[from] + return nil +} + +func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + for ; ctx != nil; ctx = ctx.parentContext { + if f := ctx.flagSet.Lookup(name); f != nil { + return ctx.flagSet + } + } + return nil +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + val, err := strconv.Atoi(f.Value.String()) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + val, err := time.ParseDuration(f.Value.String()) + if err == nil { + return val + } + } + + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + return f.Value.String() + } + + return "" +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*StringSlice)).Value() + + } + + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*IntSlice)).Value() + + } + + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + return f.Value + } + return nil +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return val + } + + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return true + } + return val + } + + return false +} + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case *StringSlice: + default: + set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := strings.Split(f.GetName(), ",") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go new file mode 100644 index 000000000..b8ab37d4e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go @@ -0,0 +1,121 @@ +package cli + +import ( + "flag" + "testing" + "time" +) + +func TestNewContext(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Int("myflag", 42, "doc") + globalCtx := NewContext(nil, globalSet, nil) + command := Command{Name: "mycommand"} + c := NewContext(nil, set, globalCtx) + c.Command = command + expect(t, c.Int("myflag"), 12) + expect(t, c.GlobalInt("myflag"), 42) + expect(t, c.Command.Name, "mycommand") +} + +func TestContext_Int(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + c := NewContext(nil, set, nil) + expect(t, c.Int("myflag"), 12) +} + +func TestContext_Duration(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Duration("myflag", time.Duration(12*time.Second), "doc") + c := NewContext(nil, set, nil) + expect(t, c.Duration("myflag"), time.Duration(12*time.Second)) +} + +func TestContext_String(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.String("myflag", "hello world", "doc") + c := NewContext(nil, set, nil) + expect(t, c.String("myflag"), "hello world") +} + +func TestContext_Bool(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := NewContext(nil, set, nil) + expect(t, c.Bool("myflag"), false) +} + +func TestContext_BoolT(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", true, "doc") + c := NewContext(nil, set, nil) + expect(t, c.BoolT("myflag"), true) +} + +func TestContext_Args(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := NewContext(nil, set, nil) + set.Parse([]string{"--myflag", "bat", "baz"}) + expect(t, len(c.Args()), 2) + expect(t, c.Bool("myflag"), true) +} + +func TestContext_NArg(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := NewContext(nil, set, nil) + set.Parse([]string{"--myflag", "bat", "baz"}) + expect(t, c.NArg(), 2) +} + +func TestContext_IsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + globalCtx := NewContext(nil, globalSet, nil) + c := NewContext(nil, set, globalCtx) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.IsSet("myflag"), true) + expect(t, c.IsSet("otherflag"), false) + expect(t, c.IsSet("bogusflag"), false) + expect(t, c.IsSet("myflagGlobal"), false) +} + +func TestContext_GlobalIsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + globalSet.Bool("myflagGlobalUnset", true, "doc") + globalCtx := NewContext(nil, globalSet, nil) + c := NewContext(nil, set, globalCtx) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.GlobalIsSet("myflag"), false) + expect(t, c.GlobalIsSet("otherflag"), false) + expect(t, c.GlobalIsSet("bogusflag"), false) + expect(t, c.GlobalIsSet("myflagGlobal"), true) + expect(t, c.GlobalIsSet("myflagGlobalUnset"), false) + expect(t, c.GlobalIsSet("bogusGlobal"), false) +} + +func TestContext_NumFlags(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + globalCtx := NewContext(nil, globalSet, nil) + c := NewContext(nil, set, globalCtx) + set.Parse([]string{"--myflag", "--otherflag=foo"}) + globalSet.Parse([]string{"--myflagGlobal"}) + expect(t, c.NumFlags(), 2) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go new file mode 100644 index 000000000..e951c2df7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go @@ -0,0 +1,546 @@ +package cli + +import ( + "flag" + "fmt" + "os" + "runtime" + "strconv" + "strings" + "time" +) + +// This flag enables bash-completion for all commands and subcommands +var BashCompletionFlag = BoolFlag{ + Name: "generate-bash-completion", +} + +// This flag prints the version for the application +var VersionFlag = BoolFlag{ + Name: "version, v", + Usage: "print the version", +} + +// This flag prints the help for all commands and subcommands +// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand +// unless HideHelp is set to true) +var HelpFlag = BoolFlag{ + Name: "help, h", + Usage: "show help", +} + +// Flag is a common interface related to parsing flags in cli. +// For more advanced flag parsing techniques, it is recommended that +// this interface be implemented. +type Flag interface { + fmt.Stringer + // Apply Flag settings to the given flag set + Apply(*flag.FlagSet) + GetName() string +} + +func flagSet(name string, flags []Flag) *flag.FlagSet { + set := flag.NewFlagSet(name, flag.ContinueOnError) + + for _, f := range flags { + f.Apply(set) + } + return set +} + +func eachName(longName string, fn func(string)) { + parts := strings.Split(longName, ",") + for _, name := range parts { + name = strings.Trim(name, " ") + fn(name) + } +} + +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// GenericFlag is the flag type for types implementing Generic +type GenericFlag struct { + Name string + Value Generic + Usage string + EnvVar string +} + +// String returns the string representation of the generic flag to display the +// help text to the user (uses the String() method of the generic flag to show +// the value) +func (f GenericFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage)) +} + +func (f GenericFlag) FormatValueHelp() string { + if f.Value == nil { + return "" + } + s := f.Value.String() + if len(s) == 0 { + return "" + } + return fmt.Sprintf("\"%s\"", s) +} + +// Apply takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) Apply(set *flag.FlagSet) { + val := f.Value + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + val.Set(envVal) + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f GenericFlag) GetName() string { + return f.Name +} + +// StringSlice is an opaque type for []string to satisfy flag.Value +type StringSlice []string + +// Set appends the string value to the list of values +func (f *StringSlice) Set(value string) error { + *f = append(*f, value) + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *StringSlice) String() string { + return fmt.Sprintf("%s", *f) +} + +// Value returns the slice of strings set by this flag +func (f *StringSlice) Value() []string { + return *f +} + +// StringSlice is a string flag that can be specified multiple times on the +// command-line +type StringSliceFlag struct { + Name string + Value *StringSlice + Usage string + EnvVar string +} + +// String returns the usage +func (f StringSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f StringSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &StringSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + newVal.Set(s) + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &StringSlice{} + } + set.Var(f.Value, name, f.Usage) + }) +} + +func (f StringSliceFlag) GetName() string { + return f.Name +} + +// StringSlice is an opaque type for []int to satisfy flag.Value +type IntSlice []int + +// Set parses the value into an integer and appends it to the list of values +func (f *IntSlice) Set(value string) error { + tmp, err := strconv.Atoi(value) + if err != nil { + return err + } else { + *f = append(*f, tmp) + } + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *IntSlice) String() string { + return fmt.Sprintf("%d", *f) +} + +// Value returns the slice of ints set by this flag +func (f *IntSlice) Value() []int { + return *f +} + +// IntSliceFlag is an int flag that can be specified multiple times on the +// command-line +type IntSliceFlag struct { + Name string + Value *IntSlice + Usage string + EnvVar string +} + +// String returns the usage +func (f IntSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f IntSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &IntSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + err := newVal.Set(s) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &IntSlice{} + } + set.Var(f.Value, name, f.Usage) + }) +} + +func (f IntSliceFlag) GetName() string { + return f.Name +} + +// BoolFlag is a switch that defaults to false +type BoolFlag struct { + Name string + Usage string + EnvVar string + Destination *bool +} + +// String returns a readable representation of this value (for usage defaults) +func (f BoolFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f BoolFlag) Apply(set *flag.FlagSet) { + val := false + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + } + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.BoolVar(f.Destination, name, val, f.Usage) + return + } + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolFlag) GetName() string { + return f.Name +} + +// BoolTFlag this represents a boolean flag that is true by default, but can +// still be set to false by --some-flag=false +type BoolTFlag struct { + Name string + Usage string + EnvVar string + Destination *bool +} + +// String returns a readable representation of this value (for usage defaults) +func (f BoolTFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f BoolTFlag) Apply(set *flag.FlagSet) { + val := true + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + break + } + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.BoolVar(f.Destination, name, val, f.Usage) + return + } + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolTFlag) GetName() string { + return f.Name +} + +// StringFlag represents a flag that takes as string value +type StringFlag struct { + Name string + Value string + Usage string + EnvVar string + Destination *string +} + +// String returns the usage +func (f StringFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage)) +} + +func (f StringFlag) FormatValueHelp() string { + s := f.Value + if len(s) == 0 { + return "" + } + return fmt.Sprintf("\"%s\"", s) +} + +// Apply populates the flag given the flag set and environment +func (f StringFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + f.Value = envVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.StringVar(f.Destination, name, f.Value, f.Usage) + return + } + set.String(name, f.Value, f.Usage) + }) +} + +func (f StringFlag) GetName() string { + return f.Name +} + +// IntFlag is a flag that takes an integer +// Errors if the value provided cannot be parsed +type IntFlag struct { + Name string + Value int + Usage string + EnvVar string + Destination *int +} + +// String returns the usage +func (f IntFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f IntFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err == nil { + f.Value = int(envValInt) + break + } + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.IntVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Int(name, f.Value, f.Usage) + }) +} + +func (f IntFlag) GetName() string { + return f.Name +} + +// DurationFlag is a flag that takes a duration specified in Go's duration +// format: https://golang.org/pkg/time/#ParseDuration +type DurationFlag struct { + Name string + Value time.Duration + Usage string + EnvVar string + Destination *time.Duration +} + +// String returns a readable representation of this value (for usage defaults) +func (f DurationFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f DurationFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValDuration, err := time.ParseDuration(envVal) + if err == nil { + f.Value = envValDuration + break + } + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.DurationVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Duration(name, f.Value, f.Usage) + }) +} + +func (f DurationFlag) GetName() string { + return f.Name +} + +// Float64Flag is a flag that takes an float value +// Errors if the value provided cannot be parsed +type Float64Flag struct { + Name string + Value float64 + Usage string + EnvVar string + Destination *float64 +} + +// String returns the usage +func (f Float64Flag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +// Apply populates the flag given the flag set and environment +func (f Float64Flag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValFloat, err := strconv.ParseFloat(envVal, 10) + if err == nil { + f.Value = float64(envValFloat) + } + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Float64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Float64(name, f.Value, f.Usage) + }) +} + +func (f Float64Flag) GetName() string { + return f.Name +} + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return +} + +func prefixedNames(fullName string) (prefixed string) { + parts := strings.Split(fullName, ",") + for i, name := range parts { + name = strings.Trim(name, " ") + prefixed += prefixFor(name) + name + if i < len(parts)-1 { + prefixed += ", " + } + } + return +} + +func withEnvHint(envVar, str string) string { + envText := "" + if envVar != "" { + prefix := "$" + suffix := "" + sep := ", $" + if runtime.GOOS == "windows" { + prefix = "%" + suffix = "%" + sep = "%, %" + } + envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) + } + return str + envText +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go new file mode 100644 index 000000000..3caa70a4b --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go @@ -0,0 +1,859 @@ +package cli + +import ( + "fmt" + "os" + "reflect" + "strings" + "testing" + "runtime" +) + +var boolFlagTests = []struct { + name string + expected string +}{ + {"help", "--help\t"}, + {"h", "-h\t"}, +} + +func TestBoolFlagHelpOutput(t *testing.T) { + + for _, test := range boolFlagTests { + flag := BoolFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +var stringFlagTests = []struct { + name string + value string + expected string +}{ + {"help", "", "--help \t"}, + {"h", "", "-h \t"}, + {"h", "", "-h \t"}, + {"test", "Something", "--test \"Something\"\t"}, +} + +func TestStringFlagHelpOutput(t *testing.T) { + + for _, test := range stringFlagTests { + flag := StringFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestStringFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "derp") + for _, test := range stringFlagTests { + flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"} + output := flag.String() + + expectedSuffix := " [$APP_FOO]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_FOO%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%s does not end with" + expectedSuffix, output) + } + } +} + +var stringSliceFlagTests = []struct { + name string + value *StringSlice + expected string +}{ + {"help", func() *StringSlice { + s := &StringSlice{} + s.Set("") + return s + }(), "--help [--help option --help option]\t"}, + {"h", func() *StringSlice { + s := &StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"h", func() *StringSlice { + s := &StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"test", func() *StringSlice { + s := &StringSlice{} + s.Set("Something") + return s + }(), "--test [--test option --test option]\t"}, +} + +func TestStringSliceFlagHelpOutput(t *testing.T) { + + for _, test := range stringSliceFlagTests { + flag := StringSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_QWWX", "11,4") + for _, test := range stringSliceFlagTests { + flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"} + output := flag.String() + + expectedSuffix := " [$APP_QWWX]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_QWWX%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%q does not end with" + expectedSuffix, output) + } + } +} + +var intFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestIntFlagHelpOutput(t *testing.T) { + + for _, test := range intFlagTests { + flag := IntFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestIntFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2") + for _, test := range intFlagTests { + flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + expectedSuffix := " [$APP_BAR]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_BAR%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%s does not end with" + expectedSuffix, output) + } + } +} + +var durationFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestDurationFlagHelpOutput(t *testing.T) { + + for _, test := range durationFlagTests { + flag := DurationFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2h3m6s") + for _, test := range durationFlagTests { + flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + expectedSuffix := " [$APP_BAR]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_BAR%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%s does not end with" + expectedSuffix, output) + } + } +} + +var intSliceFlagTests = []struct { + name string + value *IntSlice + expected string +}{ + {"help", &IntSlice{}, "--help [--help option --help option]\t"}, + {"h", &IntSlice{}, "-h [-h option -h option]\t"}, + {"h", &IntSlice{}, "-h [-h option -h option]\t"}, + {"test", func() *IntSlice { + i := &IntSlice{} + i.Set("9") + return i + }(), "--test [--test option --test option]\t"}, +} + +func TestIntSliceFlagHelpOutput(t *testing.T) { + + for _, test := range intSliceFlagTests { + flag := IntSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SMURF", "42,3") + for _, test := range intSliceFlagTests { + flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"} + output := flag.String() + + expectedSuffix := " [$APP_SMURF]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_SMURF%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%q does not end with" + expectedSuffix, output) + } + } +} + +var float64FlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestFloat64FlagHelpOutput(t *testing.T) { + + for _, test := range float64FlagTests { + flag := Float64Flag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAZ", "99.4") + for _, test := range float64FlagTests { + flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"} + output := flag.String() + + expectedSuffix := " [$APP_BAZ]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_BAZ%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%s does not end with" + expectedSuffix, output) + } + } +} + +var genericFlagTests = []struct { + name string + value Generic + expected string +}{ + {"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"}, + {"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"}, +} + +func TestGenericFlagHelpOutput(t *testing.T) { + + for _, test := range genericFlagTests { + flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_ZAP", "3") + for _, test := range genericFlagTests { + flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"} + output := flag.String() + + expectedSuffix := " [$APP_ZAP]" + if runtime.GOOS == "windows" { + expectedSuffix = " [%APP_ZAP%]" + } + if !strings.HasSuffix(output, expectedSuffix) { + t.Errorf("%s does not end with" + expectedSuffix, output) + } + } +} + +func TestParseMultiString(t *testing.T) { + (&App{ + Flags: []Flag{ + StringFlag{Name: "serve, s"}, + }, + Action: func(ctx *Context) { + if ctx.String("serve") != "10" { + t.Errorf("main name not set") + } + if ctx.String("s") != "10" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10"}) +} + +func TestParseDestinationString(t *testing.T) { + var dest string + a := App{ + Flags: []Flag{ + StringFlag{ + Name: "dest", + Destination: &dest, + }, + }, + Action: func(ctx *Context) { + if dest != "10" { + t.Errorf("expected destination String 10") + } + }, + } + a.Run([]string{"run", "--dest", "10"}) +} + +func TestParseMultiStringFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&App{ + Flags: []Flag{ + StringFlag{Name: "count, c", EnvVar: "APP_COUNT"}, + }, + Action: func(ctx *Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&App{ + Flags: []Flag{ + StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"}, + }, + Action: func(ctx *Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSlice(t *testing.T) { + (&App{ + Flags: []Flag{ + StringSliceFlag{Name: "serve, s", Value: &StringSlice{}}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiStringSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&App{ + Flags: []Flag{ + StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&App{ + Flags: []Flag{ + StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiInt(t *testing.T) { + a := App{ + Flags: []Flag{ + IntFlag{Name: "serve, s"}, + }, + Action: func(ctx *Context) { + if ctx.Int("serve") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("s") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10"}) +} + +func TestParseDestinationInt(t *testing.T) { + var dest int + a := App{ + Flags: []Flag{ + IntFlag{ + Name: "dest", + Destination: &dest, + }, + }, + Action: func(ctx *Context) { + if dest != 10 { + t.Errorf("expected destination Int 10") + } + }, + } + a.Run([]string{"run", "--dest", "10"}) +} + +func TestParseMultiIntFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := App{ + Flags: []Flag{ + IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := App{ + Flags: []Flag{ + IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntSlice(t *testing.T) { + (&App{ + Flags: []Flag{ + IntSliceFlag{Name: "serve, s", Value: &IntSlice{}}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiIntSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&App{ + Flags: []Flag{ + IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiIntSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&App{ + Flags: []Flag{ + IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiFloat64(t *testing.T) { + a := App{ + Flags: []Flag{ + Float64Flag{Name: "serve, s"}, + }, + Action: func(ctx *Context) { + if ctx.Float64("serve") != 10.2 { + t.Errorf("main name not set") + } + if ctx.Float64("s") != 10.2 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10.2"}) +} + +func TestParseDestinationFloat64(t *testing.T) { + var dest float64 + a := App{ + Flags: []Flag{ + Float64Flag{ + Name: "dest", + Destination: &dest, + }, + }, + Action: func(ctx *Context) { + if dest != 10.2 { + t.Errorf("expected destination Float64 10.2") + } + }, + } + a.Run([]string{"run", "--dest", "10.2"}) +} + +func TestParseMultiFloat64FromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := App{ + Flags: []Flag{ + Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiFloat64FromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := App{ + Flags: []Flag{ + Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBool(t *testing.T) { + a := App{ + Flags: []Flag{ + BoolFlag{Name: "serve, s"}, + }, + Action: func(ctx *Context) { + if ctx.Bool("serve") != true { + t.Errorf("main name not set") + } + if ctx.Bool("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseDestinationBool(t *testing.T) { + var dest bool + a := App{ + Flags: []Flag{ + BoolFlag{ + Name: "dest", + Destination: &dest, + }, + }, + Action: func(ctx *Context) { + if dest != true { + t.Errorf("expected destination Bool true") + } + }, + } + a.Run([]string{"run", "--dest"}) +} + +func TestParseMultiBoolFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := App{ + Flags: []Flag{ + BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := App{ + Flags: []Flag{ + BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolT(t *testing.T) { + a := App{ + Flags: []Flag{ + BoolTFlag{Name: "serve, s"}, + }, + Action: func(ctx *Context) { + if ctx.BoolT("serve") != true { + t.Errorf("main name not set") + } + if ctx.BoolT("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseDestinationBoolT(t *testing.T) { + var dest bool + a := App{ + Flags: []Flag{ + BoolTFlag{ + Name: "dest", + Destination: &dest, + }, + }, + Action: func(ctx *Context) { + if dest != true { + t.Errorf("expected destination BoolT true") + } + }, + } + a.Run([]string{"run", "--dest"}) +} + +func TestParseMultiBoolTFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := App{ + Flags: []Flag{ + BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolTFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := App{ + Flags: []Flag{ + BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +type Parser [2]string + +func (p *Parser) Set(value string) error { + parts := strings.Split(value, ",") + if len(parts) != 2 { + return fmt.Errorf("invalid format") + } + + (*p)[0] = parts[0] + (*p)[1] = parts[1] + + return nil +} + +func (p *Parser) String() string { + return fmt.Sprintf("%s,%s", p[0], p[1]) +} + +func TestParseGeneric(t *testing.T) { + a := App{ + Flags: []Flag{ + GenericFlag{Name: "serve, s", Value: &Parser{}}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10,20"}) +} + +func TestParseGenericFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SERVE", "20,30") + a := App{ + Flags: []Flag{ + GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseGenericFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "99,2000") + a := App{ + Flags: []Flag{ + GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"}, + }, + Action: func(ctx *Context) { + if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) { + t.Errorf("value not set from env") + } + }, + } + a.Run([]string{"run"}) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/help.go b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go new file mode 100644 index 000000000..15916f86a --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go @@ -0,0 +1,248 @@ +package cli + +import ( + "fmt" + "io" + "strings" + "text/tabwriter" + "text/template" +) + +// The text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var AppHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} + {{if .Version}} +VERSION: + {{.Version}} + {{end}}{{if len .Authors}} +AUTHOR(S): + {{range .Authors}}{{ . }}{{end}} + {{end}}{{if .Commands}} +COMMANDS: + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .Flags}} +GLOBAL OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}}{{if .Copyright }} +COPYRIGHT: + {{.Copyright}} + {{end}} +` + +// The text template for the command help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var CommandHelpTemplate = `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if .Flags}} + +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{ end }} +` + +// The text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + +COMMANDS: + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{if .Flags}} +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}} +` + +var helpCommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + ArgsUsage: "[command]", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowAppHelp(c) + } + }, +} + +var helpSubcommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + ArgsUsage: "[command]", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowSubcommandHelp(c) + } + }, +} + +// Prints help for the App or Command +type helpPrinter func(w io.Writer, templ string, data interface{}) + +var HelpPrinter helpPrinter = printHelp + +// Prints version for the App +var VersionPrinter = printVersion + +func ShowAppHelp(c *Context) { + HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) +} + +// Prints the list of subcommands as the default app completion method +func DefaultAppComplete(c *Context) { + for _, command := range c.App.Commands { + for _, name := range command.Names() { + fmt.Fprintln(c.App.Writer, name) + } + } +} + +// Prints help for the given command +func ShowCommandHelp(ctx *Context, command string) { + // show the subcommand help for a command with subcommands + if command == "" { + HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) + return + } + + for _, c := range ctx.App.Commands { + if c.HasName(command) { + HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + return + } + } + + if ctx.App.CommandNotFound != nil { + ctx.App.CommandNotFound(ctx, command) + } else { + fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command) + } +} + +// Prints help for the given subcommand +func ShowSubcommandHelp(c *Context) { + ShowCommandHelp(c, c.Command.Name) +} + +// Prints the version number of the App +func ShowVersion(c *Context) { + VersionPrinter(c) +} + +func printVersion(c *Context) { + fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) +} + +// Prints the lists of commands within a given context +func ShowCompletions(c *Context) { + a := c.App + if a != nil && a.BashComplete != nil { + a.BashComplete(c) + } +} + +// Prints the custom completions for a given command +func ShowCommandCompletions(ctx *Context, command string) { + c := ctx.App.Command(command) + if c != nil && c.BashComplete != nil { + c.BashComplete(ctx) + } +} + +func printHelp(out io.Writer, templ string, data interface{}) { + funcMap := template.FuncMap{ + "join": strings.Join, + } + + w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0) + t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) + err := t.Execute(w, data) + if err != nil { + // If the writer is closed, t.Execute will fail, and there's nothing + // we can do to recover. We could send this to os.Stderr if we need. + return + } + w.Flush() +} + +func checkVersion(c *Context) bool { + found := false + if VersionFlag.Name != "" { + eachName(VersionFlag.Name, func(name string) { + if c.GlobalBool(name) || c.Bool(name) { + found = true + } + }) + } + return found +} + +func checkHelp(c *Context) bool { + found := false + if HelpFlag.Name != "" { + eachName(HelpFlag.Name, func(name string) { + if c.GlobalBool(name) || c.Bool(name) { + found = true + } + }) + } + return found +} + +func checkCommandHelp(c *Context, name string) bool { + if c.Bool("h") || c.Bool("help") { + ShowCommandHelp(c, name) + return true + } + + return false +} + +func checkSubcommandHelp(c *Context) bool { + if c.GlobalBool("h") || c.GlobalBool("help") { + ShowSubcommandHelp(c) + return true + } + + return false +} + +func checkCompletions(c *Context) bool { + if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { + ShowCompletions(c) + return true + } + + return false +} + +func checkCommandCompletions(c *Context, name string) bool { + if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { + ShowCommandCompletions(c, name) + return true + } + + return false +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go new file mode 100644 index 000000000..350e2633e --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go @@ -0,0 +1,94 @@ +package cli + +import ( + "bytes" + "testing" +) + +func Test_ShowAppHelp_NoAuthor(t *testing.T) { + output := new(bytes.Buffer) + app := NewApp() + app.Writer = output + + c := NewContext(app, nil, nil) + + ShowAppHelp(c) + + if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 { + t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):") + } +} + +func Test_ShowAppHelp_NoVersion(t *testing.T) { + output := new(bytes.Buffer) + app := NewApp() + app.Writer = output + + app.Version = "" + + c := NewContext(app, nil, nil) + + ShowAppHelp(c) + + if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 { + t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") + } +} + +func Test_Help_Custom_Flags(t *testing.T) { + oldFlag := HelpFlag + defer func() { + HelpFlag = oldFlag + }() + + HelpFlag = BoolFlag{ + Name: "help, x", + Usage: "show help", + } + + app := App{ + Flags: []Flag{ + BoolFlag{Name: "foo, h"}, + }, + Action: func(ctx *Context) { + if ctx.Bool("h") != true { + t.Errorf("custom help flag not set") + } + }, + } + output := new(bytes.Buffer) + app.Writer = output + app.Run([]string{"test", "-h"}) + if output.Len() > 0 { + t.Errorf("unexpected output: %s", output.String()) + } +} + +func Test_Version_Custom_Flags(t *testing.T) { + oldFlag := VersionFlag + defer func() { + VersionFlag = oldFlag + }() + + VersionFlag = BoolFlag{ + Name: "version, V", + Usage: "show version", + } + + app := App{ + Flags: []Flag{ + BoolFlag{Name: "foo, v"}, + }, + Action: func(ctx *Context) { + if ctx.Bool("v") != true { + t.Errorf("custom version flag not set") + } + }, + } + output := new(bytes.Buffer) + app.Writer = output + app.Run([]string{"test", "-v"}) + if output.Len() > 0 { + t.Errorf("unexpected output: %s", output.String()) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go new file mode 100644 index 000000000..b1b7339f2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go @@ -0,0 +1,19 @@ +package cli + +import ( + "reflect" + "testing" +) + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if !reflect.DeepEqual(a, b) { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if reflect.DeepEqual(a, b) { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} diff --git a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver.go b/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver.go deleted file mode 100644 index f1f8ab797..000000000 --- a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver.go +++ /dev/null @@ -1,209 +0,0 @@ -package semver - -import ( - "bytes" - "errors" - "fmt" - "strconv" - "strings" -) - -type Version struct { - Major int64 - Minor int64 - Patch int64 - PreRelease PreRelease - Metadata string -} - -type PreRelease string - -func splitOff(input *string, delim string) (val string) { - parts := strings.SplitN(*input, delim, 2) - - if len(parts) == 2 { - *input = parts[0] - val = parts[1] - } - - return val -} - -func NewVersion(version string) (*Version, error) { - v := Version{} - - dotParts := strings.SplitN(version, ".", 3) - - if len(dotParts) != 3 { - return nil, errors.New(fmt.Sprintf("%s is not in dotted-tri format", version)) - } - - v.Metadata = splitOff(&dotParts[2], "+") - v.PreRelease = PreRelease(splitOff(&dotParts[2], "-")) - - parsed := make([]int64, 3, 3) - - for i, v := range dotParts[:3] { - val, err := strconv.ParseInt(v, 10, 64) - parsed[i] = val - if err != nil { - return nil, err - } - } - - v.Major = parsed[0] - v.Minor = parsed[1] - v.Patch = parsed[2] - - return &v, nil -} - -func Must(v *Version, err error) *Version { - if err != nil { - panic(err) - } - return v -} - -func (v *Version) String() string { - var buffer bytes.Buffer - - base := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) - buffer.WriteString(base) - - if v.PreRelease != "" { - buffer.WriteString(fmt.Sprintf("-%s", v.PreRelease)) - } - - if v.Metadata != "" { - buffer.WriteString(fmt.Sprintf("+%s", v.Metadata)) - } - - return buffer.String() -} - -func (v *Version) LessThan(versionB Version) bool { - versionA := *v - cmp := recursiveCompare(versionA.Slice(), versionB.Slice()) - - if cmp == 0 { - cmp = preReleaseCompare(versionA, versionB) - } - - if cmp == -1 { - return true - } - - return false -} - -/* Slice converts the comparable parts of the semver into a slice of strings */ -func (v *Version) Slice() []int64 { - return []int64{v.Major, v.Minor, v.Patch} -} - -func (p *PreRelease) Slice() []string { - preRelease := string(*p) - return strings.Split(preRelease, ".") -} - -func preReleaseCompare(versionA Version, versionB Version) int { - a := versionA.PreRelease - b := versionB.PreRelease - - /* Handle the case where if two versions are otherwise equal it is the - * one without a PreRelease that is greater */ - if len(a) == 0 && (len(b) > 0) { - return 1 - } else if len(b) == 0 && (len(a) > 0) { - return -1 - } - - // If there is a prelease, check and compare each part. - return recursivePreReleaseCompare(a.Slice(), b.Slice()) -} - -func recursiveCompare(versionA []int64, versionB []int64) int { - if len(versionA) == 0 { - return 0 - } - - a := versionA[0] - b := versionB[0] - - if a > b { - return 1 - } else if a < b { - return -1 - } - - return recursiveCompare(versionA[1:], versionB[1:]) -} - -func recursivePreReleaseCompare(versionA []string, versionB []string) int { - // Handle slice length disparity. - if len(versionA) == 0 { - // Nothing to compare too, so we return 0 - return 0 - } else if len(versionB) == 0 { - // We're longer than versionB so return 1. - return 1 - } - - a := versionA[0] - b := versionB[0] - - aInt := false; bInt := false - - aI, err := strconv.Atoi(versionA[0]) - if err == nil { - aInt = true - } - - bI, err := strconv.Atoi(versionB[0]) - if err == nil { - bInt = true - } - - // Handle Integer Comparison - if aInt && bInt { - if aI > bI { - return 1 - } else if aI < bI { - return -1 - } - } - - // Handle String Comparison - if a > b { - return 1 - } else if a < b { - return -1 - } - - return recursivePreReleaseCompare(versionA[1:], versionB[1:]) -} - -// BumpMajor increments the Major field by 1 and resets all other fields to their default values -func (v *Version) BumpMajor() { - v.Major += 1 - v.Minor = 0 - v.Patch = 0 - v.PreRelease = PreRelease("") - v.Metadata = "" -} - -// BumpMinor increments the Minor field by 1 and resets all other fields to their default values -func (v *Version) BumpMinor() { - v.Minor += 1 - v.Patch = 0 - v.PreRelease = PreRelease("") - v.Metadata = "" -} - -// BumpPatch increments the Patch field by 1 and resets all other fields to their default values -func (v *Version) BumpPatch() { - v.Patch += 1 - v.PreRelease = PreRelease("") - v.Metadata = "" -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver_test.go b/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver_test.go deleted file mode 100644 index 9bfc3b8a9..000000000 --- a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/semver_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package semver - -import ( - "errors" - "math/rand" - "reflect" - "testing" - "time" -) - -type fixture struct { - greaterVersion string - lesserVersion string -} - -var fixtures = []fixture{ - fixture{"0.0.0", "0.0.0-foo"}, - fixture{"0.0.1", "0.0.0"}, - fixture{"1.0.0", "0.9.9"}, - fixture{"0.10.0", "0.9.0"}, - fixture{"0.99.0", "0.10.0"}, - fixture{"2.0.0", "1.2.3"}, - fixture{"0.0.0", "0.0.0-foo"}, - fixture{"0.0.1", "0.0.0"}, - fixture{"1.0.0", "0.9.9"}, - fixture{"0.10.0", "0.9.0"}, - fixture{"0.99.0", "0.10.0"}, - fixture{"2.0.0", "1.2.3"}, - fixture{"0.0.0", "0.0.0-foo"}, - fixture{"0.0.1", "0.0.0"}, - fixture{"1.0.0", "0.9.9"}, - fixture{"0.10.0", "0.9.0"}, - fixture{"0.99.0", "0.10.0"}, - fixture{"2.0.0", "1.2.3"}, - fixture{"1.2.3", "1.2.3-asdf"}, - fixture{"1.2.3", "1.2.3-4"}, - fixture{"1.2.3", "1.2.3-4-foo"}, - fixture{"1.2.3-5-foo", "1.2.3-5"}, - fixture{"1.2.3-5", "1.2.3-4"}, - fixture{"1.2.3-5-foo", "1.2.3-5-Foo"}, - fixture{"3.0.0", "2.7.2+asdf"}, - fixture{"3.0.0+foobar", "2.7.2"}, - fixture{"1.2.3-a.10", "1.2.3-a.5"}, - fixture{"1.2.3-a.b", "1.2.3-a.5"}, - fixture{"1.2.3-a.b", "1.2.3-a"}, - fixture{"1.2.3-a.b.c.10.d.5", "1.2.3-a.b.c.5.d.100"}, - fixture{"1.0.0", "1.0.0-rc.1"}, - fixture{"1.0.0-rc.2", "1.0.0-rc.1"}, - fixture{"1.0.0-rc.1", "1.0.0-beta.11"}, - fixture{"1.0.0-beta.11", "1.0.0-beta.2"}, - fixture{"1.0.0-beta.2", "1.0.0-beta"}, - fixture{"1.0.0-beta", "1.0.0-alpha.beta"}, - fixture{"1.0.0-alpha.beta", "1.0.0-alpha.1"}, - fixture{"1.0.0-alpha.1", "1.0.0-alpha"}, -} - -func TestCompare(t *testing.T) { - for _, v := range fixtures { - gt, err := NewVersion(v.greaterVersion) - if err != nil { - t.Error(err) - } - - lt, err := NewVersion(v.lesserVersion) - if err != nil { - t.Error(err) - } - - if gt.LessThan(*lt) == true { - t.Errorf("%s should not be less than %s", gt, lt) - } - } -} - -func testString(t *testing.T, orig string, version *Version) { - if orig != version.String() { - t.Errorf("%s != %s", orig, version) - } -} - -func TestString(t *testing.T) { - for _, v := range fixtures { - gt, err := NewVersion(v.greaterVersion) - if err != nil { - t.Error(err) - } - testString(t, v.greaterVersion, gt) - - lt, err := NewVersion(v.lesserVersion) - if err != nil { - t.Error(err) - } - testString(t, v.lesserVersion, lt) - } -} - -func shuffleStringSlice(src []string) []string { - dest := make([]string, len(src)) - rand.Seed(time.Now().Unix()) - perm := rand.Perm(len(src)) - for i, v := range perm { - dest[v] = src[i] - } - return dest -} - -func TestSort(t *testing.T) { - sortedVersions := []string{"1.0.0", "1.0.2", "1.2.0", "3.1.1"} - unsortedVersions := shuffleStringSlice(sortedVersions) - - semvers := []*Version{} - for _, v := range unsortedVersions { - sv, err := NewVersion(v) - if err != nil { - t.Fatal(err) - } - semvers = append(semvers, sv) - } - - Sort(semvers) - - for idx, sv := range semvers { - if sv.String() != sortedVersions[idx] { - t.Fatalf("incorrect sort at index %v", idx) - } - } -} - -func TestBumpMajor(t *testing.T) { - version, _ := NewVersion("1.0.0") - version.BumpMajor() - if version.Major != 2 { - t.Fatalf("bumping major on 1.0.0 resulted in %v", version) - } - - version, _ = NewVersion("1.5.2") - version.BumpMajor() - if version.Minor != 0 && version.Patch != 0 { - t.Fatalf("bumping major on 1.5.2 resulted in %v", version) - } - - version, _ = NewVersion("1.0.0+build.1-alpha.1") - version.BumpMajor() - if version.PreRelease != "" && version.PreRelease != "" { - t.Fatalf("bumping major on 1.0.0+build.1-alpha.1 resulted in %v", version) - } -} - -func TestBumpMinor(t *testing.T) { - version, _ := NewVersion("1.0.0") - version.BumpMinor() - - if version.Major != 1 { - t.Fatalf("bumping minor on 1.0.0 resulted in %v", version) - } - - if version.Minor != 1 { - t.Fatalf("bumping major on 1.0.0 resulted in %v", version) - } - - version, _ = NewVersion("1.0.0+build.1-alpha.1") - version.BumpMinor() - if version.PreRelease != "" && version.PreRelease != "" { - t.Fatalf("bumping major on 1.0.0+build.1-alpha.1 resulted in %v", version) - } -} - -func TestBumpPatch(t *testing.T) { - version, _ := NewVersion("1.0.0") - version.BumpPatch() - - if version.Major != 1 { - t.Fatalf("bumping minor on 1.0.0 resulted in %v", version) - } - - if version.Minor != 0 { - t.Fatalf("bumping major on 1.0.0 resulted in %v", version) - } - - if version.Patch != 1 { - t.Fatalf("bumping major on 1.0.0 resulted in %v", version) - } - - version, _ = NewVersion("1.0.0+build.1-alpha.1") - version.BumpPatch() - if version.PreRelease != "" && version.PreRelease != "" { - t.Fatalf("bumping major on 1.0.0+build.1-alpha.1 resulted in %v", version) - } -} - -func TestMust(t *testing.T) { - tests := []struct { - versionStr string - - version *Version - recov interface{} - }{ - { - versionStr: "1.0.0", - version: &Version{Major: 1}, - }, - { - versionStr: "version number", - recov: errors.New("version number is not in dotted-tri format"), - }, - } - - for _, tt := range tests { - func() { - defer func() { - recov := recover() - if !reflect.DeepEqual(tt.recov, recov) { - t.Fatalf("incorrect panic for %q: want %v, got %v", tt.versionStr, tt.recov, recov) - } - }() - - version := Must(NewVersion(tt.versionStr)) - if !reflect.DeepEqual(tt.version, version) { - t.Fatalf("incorrect version for %q: want %+v, got %+v", tt.versionStr, tt.version, version) - } - }() - } -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/sort.go b/Godeps/_workspace/src/github.com/coreos/go-semver/semver/sort.go deleted file mode 100644 index 86203007a..000000000 --- a/Godeps/_workspace/src/github.com/coreos/go-semver/semver/sort.go +++ /dev/null @@ -1,24 +0,0 @@ -package semver - -import ( - "sort" -) - -type Versions []*Version - -func (s Versions) Len() int { - return len(s) -} - -func (s Versions) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s Versions) Less(i, j int) bool { - return s[i].LessThan(*s[j]) -} - -// Sort sorts the given slice of Version -func Sort(versions []*Version) { - sort.Sort(Versions(versions)) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt.go deleted file mode 100644 index c0654f5d8..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt.go +++ /dev/null @@ -1,74 +0,0 @@ -package aws - -import ( - "time" -) - -// AttemptStrategy represents a strategy for waiting for an action -// to complete successfully. This is an internal type used by the -// implementation of other goamz packages. -type AttemptStrategy struct { - Total time.Duration // total duration of attempt. - Delay time.Duration // interval between each try in the burst. - Min int // minimum number of retries; overrides Total -} - -type Attempt struct { - strategy AttemptStrategy - last time.Time - end time.Time - force bool - count int -} - -// Start begins a new sequence of attempts for the given strategy. -func (s AttemptStrategy) Start() *Attempt { - now := time.Now() - return &Attempt{ - strategy: s, - last: now, - end: now.Add(s.Total), - force: true, - } -} - -// Next waits until it is time to perform the next attempt or returns -// false if it is time to stop trying. -func (a *Attempt) Next() bool { - now := time.Now() - sleep := a.nextSleep(now) - if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count { - return false - } - a.force = false - if sleep > 0 && a.count > 0 { - time.Sleep(sleep) - now = time.Now() - } - a.count++ - a.last = now - return true -} - -func (a *Attempt) nextSleep(now time.Time) time.Duration { - sleep := a.strategy.Delay - now.Sub(a.last) - if sleep < 0 { - return 0 - } - return sleep -} - -// HasNext returns whether another attempt will be made if the current -// one fails. If it returns true, the following call to Next is -// guaranteed to return true. -func (a *Attempt) HasNext() bool { - if a.force || a.strategy.Min > a.count { - return true - } - now := time.Now() - if now.Add(a.nextSleep(now)).Before(a.end) { - a.force = true - return true - } - return false -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt_test.go deleted file mode 100644 index fc58ebe21..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/attempt_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package aws_test - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "gopkg.in/check.v1" - "time" -) - -func (S) TestAttemptTiming(c *check.C) { - testAttempt := aws.AttemptStrategy{ - Total: 0.25e9, - Delay: 0.1e9, - } - want := []time.Duration{0, 0.1e9, 0.2e9, 0.2e9} - got := make([]time.Duration, 0, len(want)) // avoid allocation when testing timing - t0 := time.Now() - for a := testAttempt.Start(); a.Next(); { - got = append(got, time.Now().Sub(t0)) - } - got = append(got, time.Now().Sub(t0)) - c.Assert(got, check.HasLen, len(want)) - const margin = 0.01e9 - for i, got := range want { - lo := want[i] - margin - hi := want[i] + margin - if got < lo || got > hi { - c.Errorf("attempt %d want %g got %g", i, want[i].Seconds(), got.Seconds()) - } - } -} - -func (S) TestAttemptNextHasNext(c *check.C) { - a := aws.AttemptStrategy{}.Start() - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.Next(), check.Equals, false) - - a = aws.AttemptStrategy{}.Start() - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.HasNext(), check.Equals, false) - c.Assert(a.Next(), check.Equals, false) - - a = aws.AttemptStrategy{Total: 2e8}.Start() - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.HasNext(), check.Equals, true) - time.Sleep(2e8) - c.Assert(a.HasNext(), check.Equals, true) - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.Next(), check.Equals, false) - - a = aws.AttemptStrategy{Total: 1e8, Min: 2}.Start() - time.Sleep(1e8) - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.HasNext(), check.Equals, true) - c.Assert(a.Next(), check.Equals, true) - c.Assert(a.HasNext(), check.Equals, false) - c.Assert(a.Next(), check.Equals, false) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws.go deleted file mode 100644 index 38c9e6566..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws.go +++ /dev/null @@ -1,624 +0,0 @@ -// -// goamz - Go packages to interact with the Amazon Web Services. -// -// https://wiki.ubuntu.com/goamz -// -// Copyright (c) 2011 Canonical Ltd. -// -// Written by Gustavo Niemeyer -// -package aws - -import ( - "encoding/json" - "encoding/xml" - "errors" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "os/user" - "path" - "regexp" - "strings" - "time" -) - -// Regular expressions for INI files -var ( - iniSectionRegexp = regexp.MustCompile(`^\s*\[([^\[\]]+)\]\s*$`) - iniSettingRegexp = regexp.MustCompile(`^\s*(.+?)\s*=\s*(.*\S)\s*$`) -) - -// Defines the valid signers -const ( - V2Signature = iota - V4Signature = iota - Route53Signature = iota -) - -// Defines the service endpoint and correct Signer implementation to use -// to sign requests for this endpoint -type ServiceInfo struct { - Endpoint string - Signer uint -} - -// Region defines the URLs where AWS services may be accessed. -// -// See http://goo.gl/d8BP1 for more details. -type Region struct { - Name string // the canonical name of this region. - EC2Endpoint string - S3Endpoint string - S3BucketEndpoint string // Not needed by AWS S3. Use ${bucket} for bucket name. - S3LocationConstraint bool // true if this region requires a LocationConstraint declaration. - S3LowercaseBucket bool // true if the region requires bucket names to be lower case. - SDBEndpoint string - SNSEndpoint string - SQSEndpoint string - SESEndpoint string - IAMEndpoint string - ELBEndpoint string - DynamoDBEndpoint string - CloudWatchServicepoint ServiceInfo - AutoScalingEndpoint string - RDSEndpoint ServiceInfo - KinesisEndpoint string - STSEndpoint string - CloudFormationEndpoint string - ElastiCacheEndpoint string -} - -var Regions = map[string]Region{ - APNortheast.Name: APNortheast, - APSoutheast.Name: APSoutheast, - APSoutheast2.Name: APSoutheast2, - EUCentral.Name: EUCentral, - EUWest.Name: EUWest, - USEast.Name: USEast, - USWest.Name: USWest, - USWest2.Name: USWest2, - USGovWest.Name: USGovWest, - SAEast.Name: SAEast, -} - -// Designates a signer interface suitable for signing AWS requests, params -// should be appropriately encoded for the request before signing. -// -// A signer should be initialized with Auth and the appropriate endpoint. -type Signer interface { - Sign(method, path string, params map[string]string) -} - -// An AWS Service interface with the API to query the AWS service -// -// Supplied as an easy way to mock out service calls during testing. -type AWSService interface { - // Queries the AWS service at a given method/path with the params and - // returns an http.Response and error - Query(method, path string, params map[string]string) (*http.Response, error) - // Builds an error given an XML payload in the http.Response, can be used - // to process an error if the status code is not 200 for example. - BuildError(r *http.Response) error -} - -// Implements a Server Query/Post API to easily query AWS services and build -// errors when desired -type Service struct { - service ServiceInfo - signer Signer -} - -// Create a base set of params for an action -func MakeParams(action string) map[string]string { - params := make(map[string]string) - params["Action"] = action - return params -} - -// Create a new AWS server to handle making requests -func NewService(auth Auth, service ServiceInfo) (s *Service, err error) { - var signer Signer - switch service.Signer { - case V2Signature: - signer, err = NewV2Signer(auth, service) - // case V4Signature: - // signer, err = NewV4Signer(auth, service, Regions["eu-west-1"]) - default: - err = fmt.Errorf("Unsupported signer for service") - } - if err != nil { - return - } - s = &Service{service: service, signer: signer} - return -} - -func (s *Service) Query(method, path string, params map[string]string) (resp *http.Response, err error) { - params["Timestamp"] = time.Now().UTC().Format(time.RFC3339) - u, err := url.Parse(s.service.Endpoint) - if err != nil { - return nil, err - } - u.Path = path - - s.signer.Sign(method, path, params) - if method == "GET" { - u.RawQuery = multimap(params).Encode() - resp, err = http.Get(u.String()) - } else if method == "POST" { - resp, err = http.PostForm(u.String(), multimap(params)) - } - - return -} - -func (s *Service) BuildError(r *http.Response) error { - errors := ErrorResponse{} - xml.NewDecoder(r.Body).Decode(&errors) - var err Error - err = errors.Errors - err.RequestId = errors.RequestId - err.StatusCode = r.StatusCode - if err.Message == "" { - err.Message = r.Status - } - return &err -} - -type ServiceError interface { - error - ErrorCode() string -} - -type ErrorResponse struct { - Errors Error `xml:"Error"` - RequestId string // A unique ID for tracking the request -} - -type Error struct { - StatusCode int - Type string - Code string - Message string - RequestId string -} - -func (err *Error) Error() string { - return fmt.Sprintf("Type: %s, Code: %s, Message: %s", - err.Type, err.Code, err.Message, - ) -} - -func (err *Error) ErrorCode() string { - return err.Code -} - -type Auth struct { - AccessKey, SecretKey string - token string - expiration time.Time -} - -func (a *Auth) Token() string { - if a.token == "" { - return "" - } - if time.Since(a.expiration) >= -30*time.Second { //in an ideal world this should be zero assuming the instance is synching it's clock - *a, _ = GetAuth("", "", "", time.Time{}) - } - return a.token -} - -func (a *Auth) Expiration() time.Time { - return a.expiration -} - -// To be used with other APIs that return auth credentials such as STS -func NewAuth(accessKey, secretKey, token string, expiration time.Time) *Auth { - return &Auth{ - AccessKey: accessKey, - SecretKey: secretKey, - token: token, - expiration: expiration, - } -} - -// ResponseMetadata -type ResponseMetadata struct { - RequestId string // A unique ID for tracking the request -} - -type BaseResponse struct { - ResponseMetadata ResponseMetadata -} - -var unreserved = make([]bool, 128) -var hex = "0123456789ABCDEF" - -func init() { - // RFC3986 - u := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_.~" - for _, c := range u { - unreserved[c] = true - } -} - -func multimap(p map[string]string) url.Values { - q := make(url.Values, len(p)) - for k, v := range p { - q[k] = []string{v} - } - return q -} - -type credentials struct { - Code string - LastUpdated string - Type string - AccessKeyId string - SecretAccessKey string - Token string - Expiration string -} - -// GetMetaData retrieves instance metadata about the current machine. -// -// See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html for more details. -func GetMetaData(path string) (contents []byte, err error) { - c := http.Client{ - Transport: &http.Transport{ - Dial: func(netw, addr string) (net.Conn, error) { - deadline := time.Now().Add(5 * time.Second) - c, err := net.DialTimeout(netw, addr, time.Second*2) - if err != nil { - return nil, err - } - c.SetDeadline(deadline) - return c, nil - }, - }, - } - - url := "http://169.254.169.254/latest/meta-data/" + path - - resp, err := c.Get(url) - if err != nil { - return - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url) - return - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return - } - return []byte(body), err -} - -func GetRegion(regionName string) (region Region) { - region = Regions[regionName] - return -} - -// GetInstanceCredentials creates an Auth based on the instance's role credentials. -// If the running instance is not in EC2 or does not have a valid IAM role, an error will be returned. -// For more info about setting up IAM roles, see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html -func GetInstanceCredentials() (cred credentials, err error) { - credentialPath := "iam/security-credentials/" - - // Get the instance role - role, err := GetMetaData(credentialPath) - if err != nil { - return - } - - // Get the instance role credentials - credentialJSON, err := GetMetaData(credentialPath + string(role)) - if err != nil { - return - } - - err = json.Unmarshal([]byte(credentialJSON), &cred) - return -} - -// GetAuth creates an Auth based on either passed in credentials, -// environment information or instance based role credentials. -func GetAuth(accessKey string, secretKey, token string, expiration time.Time) (auth Auth, err error) { - // First try passed in credentials - if accessKey != "" && secretKey != "" { - return Auth{accessKey, secretKey, token, expiration}, nil - } - - // Next try to get auth from the environment - auth, err = EnvAuth() - if err == nil { - // Found auth, return - return - } - - // Next try getting auth from the instance role - cred, err := GetInstanceCredentials() - if err == nil { - // Found auth, return - auth.AccessKey = cred.AccessKeyId - auth.SecretKey = cred.SecretAccessKey - auth.token = cred.Token - exptdate, err := time.Parse("2006-01-02T15:04:05Z", cred.Expiration) - if err != nil { - err = fmt.Errorf("Error Parsing expiration date: cred.Expiration :%s , error: %s \n", cred.Expiration, err) - } - auth.expiration = exptdate - return auth, err - } - - // Next try getting auth from the credentials file - auth, err = CredentialFileAuth("", "", time.Minute*5) - if err == nil { - return - } - - //err = errors.New("No valid AWS authentication found") - err = fmt.Errorf("No valid AWS authentication found: %s", err) - return auth, err -} - -// EnvAuth creates an Auth based on environment information. -// The AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment -// variables are used. -func EnvAuth() (auth Auth, err error) { - auth.AccessKey = os.Getenv("AWS_ACCESS_KEY_ID") - if auth.AccessKey == "" { - auth.AccessKey = os.Getenv("AWS_ACCESS_KEY") - } - - auth.SecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") - if auth.SecretKey == "" { - auth.SecretKey = os.Getenv("AWS_SECRET_KEY") - } - if auth.AccessKey == "" { - err = errors.New("AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment") - } - if auth.SecretKey == "" { - err = errors.New("AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment") - } - return -} - -// CredentialFileAuth creates and Auth based on a credentials file. The file -// contains various authentication profiles for use with AWS. -// -// The credentials file, which is used by other AWS SDKs, is documented at -// http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs -func CredentialFileAuth(filePath string, profile string, expiration time.Duration) (auth Auth, err error) { - if profile == "" { - profile = "default" - } - - if filePath == "" { - u, err := user.Current() - if err != nil { - return auth, err - } - - filePath = path.Join(u.HomeDir, ".aws", "credentials") - } - - // read the file, then parse the INI - contents, err := ioutil.ReadFile(filePath) - if err != nil { - return - } - - profiles := parseINI(string(contents)) - profileData, ok := profiles[profile] - - if !ok { - err = errors.New("The credentials file did not contain the profile") - return - } - - keyId, ok := profileData["aws_access_key_id"] - if !ok { - err = errors.New("The credentials file did not contain required attribute aws_access_key_id") - return - } - - secretKey, ok := profileData["aws_secret_access_key"] - if !ok { - err = errors.New("The credentials file did not contain required attribute aws_secret_access_key") - return - } - - auth.AccessKey = keyId - auth.SecretKey = secretKey - - if token, ok := profileData["aws_session_token"]; ok { - auth.token = token - } - - auth.expiration = time.Now().Add(expiration) - - return -} - -// parseINI takes the contents of a credentials file and returns a map, whose keys -// are the various profiles, and whose values are maps of the settings for the -// profiles -func parseINI(fileContents string) map[string]map[string]string { - profiles := make(map[string]map[string]string) - - lines := strings.Split(fileContents, "\n") - - var currentSection map[string]string - for _, line := range lines { - // remove comments, which start with a semi-colon - if split := strings.Split(line, ";"); len(split) > 1 { - line = split[0] - } - - // check if the line is the start of a profile. - // - // for example: - // [default] - // - // otherwise, check for the proper setting - // property=value - if sectMatch := iniSectionRegexp.FindStringSubmatch(line); len(sectMatch) == 2 { - currentSection = make(map[string]string) - profiles[sectMatch[1]] = currentSection - } else if setMatch := iniSettingRegexp.FindStringSubmatch(line); len(setMatch) == 3 && currentSection != nil { - currentSection[setMatch[1]] = setMatch[2] - } - } - - return profiles -} - -// Encode takes a string and URI-encodes it in a way suitable -// to be used in AWS signatures. -func Encode(s string) string { - encode := false - for i := 0; i != len(s); i++ { - c := s[i] - if c > 127 || !unreserved[c] { - encode = true - break - } - } - if !encode { - return s - } - e := make([]byte, len(s)*3) - ei := 0 - for i := 0; i != len(s); i++ { - c := s[i] - if c > 127 || !unreserved[c] { - e[ei] = '%' - e[ei+1] = hex[c>>4] - e[ei+2] = hex[c&0xF] - ei += 3 - } else { - e[ei] = c - ei += 1 - } - } - return string(e[:ei]) -} - -func dialTimeout(network, addr string) (net.Conn, error) { - return net.DialTimeout(network, addr, time.Duration(2*time.Second)) -} - -func AvailabilityZone() string { - transport := http.Transport{Dial: dialTimeout} - client := http.Client{ - Transport: &transport, - } - resp, err := client.Get("http://169.254.169.254/latest/meta-data/placement/availability-zone") - if err != nil { - return "unknown" - } else { - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "unknown" - } else { - return string(body) - } - } -} - -func InstanceRegion() string { - az := AvailabilityZone() - if az == "unknown" { - return az - } else { - region := az[:len(az)-1] - return region - } -} - -func InstanceId() string { - transport := http.Transport{Dial: dialTimeout} - client := http.Client{ - Transport: &transport, - } - resp, err := client.Get("http://169.254.169.254/latest/meta-data/instance-id") - if err != nil { - return "unknown" - } else { - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "unknown" - } else { - return string(body) - } - } -} - -func InstanceType() string { - transport := http.Transport{Dial: dialTimeout} - client := http.Client{ - Transport: &transport, - } - resp, err := client.Get("http://169.254.169.254/latest/meta-data/instance-type") - if err != nil { - return "unknown" - } else { - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "unknown" - } else { - return string(body) - } - } -} - -func ServerLocalIp() string { - transport := http.Transport{Dial: dialTimeout} - client := http.Client{ - Transport: &transport, - } - resp, err := client.Get("http://169.254.169.254/latest/meta-data/local-ipv4") - if err != nil { - return "127.0.0.1" - } else { - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "127.0.0.1" - } else { - return string(body) - } - } -} - -func ServerPublicIp() string { - transport := http.Transport{Dial: dialTimeout} - client := http.Client{ - Transport: &transport, - } - resp, err := client.Get("http://169.254.169.254/latest/meta-data/public-ipv4") - if err != nil { - return "127.0.0.1" - } else { - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "127.0.0.1" - } else { - return string(body) - } - } -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws_test.go deleted file mode 100644 index 92fbe32d7..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/aws_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package aws_test - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "gopkg.in/check.v1" - "io/ioutil" - "os" - "strings" - "testing" - "time" -) - -func Test(t *testing.T) { - check.TestingT(t) -} - -var _ = check.Suite(&S{}) - -type S struct { - environ []string -} - -func (s *S) SetUpSuite(c *check.C) { - s.environ = os.Environ() -} - -func (s *S) TearDownTest(c *check.C) { - os.Clearenv() - for _, kv := range s.environ { - l := strings.SplitN(kv, "=", 2) - os.Setenv(l[0], l[1]) - } -} - -func (s *S) TestEnvAuthNoSecret(c *check.C) { - os.Clearenv() - _, err := aws.EnvAuth() - c.Assert(err, check.ErrorMatches, "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment") -} - -func (s *S) TestEnvAuthNoAccess(c *check.C) { - os.Clearenv() - os.Setenv("AWS_SECRET_ACCESS_KEY", "foo") - _, err := aws.EnvAuth() - c.Assert(err, check.ErrorMatches, "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment") -} - -func (s *S) TestEnvAuth(c *check.C) { - os.Clearenv() - os.Setenv("AWS_SECRET_ACCESS_KEY", "secret") - os.Setenv("AWS_ACCESS_KEY_ID", "access") - auth, err := aws.EnvAuth() - c.Assert(err, check.IsNil) - c.Assert(auth, check.Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"}) -} - -func (s *S) TestEnvAuthAlt(c *check.C) { - os.Clearenv() - os.Setenv("AWS_SECRET_KEY", "secret") - os.Setenv("AWS_ACCESS_KEY", "access") - auth, err := aws.EnvAuth() - c.Assert(err, check.IsNil) - c.Assert(auth, check.Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"}) -} - -func (s *S) TestGetAuthStatic(c *check.C) { - exptdate := time.Now().Add(time.Hour) - auth, err := aws.GetAuth("access", "secret", "token", exptdate) - c.Assert(err, check.IsNil) - c.Assert(auth.AccessKey, check.Equals, "access") - c.Assert(auth.SecretKey, check.Equals, "secret") - c.Assert(auth.Token(), check.Equals, "token") - c.Assert(auth.Expiration(), check.Equals, exptdate) -} - -func (s *S) TestGetAuthEnv(c *check.C) { - os.Clearenv() - os.Setenv("AWS_SECRET_ACCESS_KEY", "secret") - os.Setenv("AWS_ACCESS_KEY_ID", "access") - auth, err := aws.GetAuth("", "", "", time.Time{}) - c.Assert(err, check.IsNil) - c.Assert(auth, check.Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"}) -} - -func (s *S) TestEncode(c *check.C) { - c.Assert(aws.Encode("foo"), check.Equals, "foo") - c.Assert(aws.Encode("/"), check.Equals, "%2F") -} - -func (s *S) TestRegionsAreNamed(c *check.C) { - for n, r := range aws.Regions { - c.Assert(n, check.Equals, r.Name) - } -} - -func (s *S) TestCredentialsFileAuth(c *check.C) { - file, err := ioutil.TempFile("", "creds") - - if err != nil { - c.Fatal(err) - } - - iniFile := ` - -[default] ; comment 123 -aws_access_key_id = keyid1 ;comment -aws_secret_access_key=key1 - - [profile2] - aws_access_key_id = keyid2 ;comment - aws_secret_access_key=key2 - aws_session_token=token1 - -` - _, err = file.WriteString(iniFile) - if err != nil { - c.Fatal(err) - } - - err = file.Close() - if err != nil { - c.Fatal(err) - } - - // check non-existant profile - _, err = aws.CredentialFileAuth(file.Name(), "no profile", 30*time.Minute) - c.Assert(err, check.Not(check.Equals), nil) - - defaultProfile, err := aws.CredentialFileAuth(file.Name(), "default", 30*time.Minute) - c.Assert(err, check.Equals, nil) - c.Assert(defaultProfile.AccessKey, check.Equals, "keyid1") - c.Assert(defaultProfile.SecretKey, check.Equals, "key1") - c.Assert(defaultProfile.Token(), check.Equals, "") - - profile2, err := aws.CredentialFileAuth(file.Name(), "profile2", 30*time.Minute) - c.Assert(err, check.Equals, nil) - c.Assert(profile2.AccessKey, check.Equals, "keyid2") - c.Assert(profile2.SecretKey, check.Equals, "key2") - c.Assert(profile2.Token(), check.Equals, "token1") -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/client.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/client.go deleted file mode 100644 index 86d2ccec8..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/client.go +++ /dev/null @@ -1,124 +0,0 @@ -package aws - -import ( - "math" - "net" - "net/http" - "time" -) - -type RetryableFunc func(*http.Request, *http.Response, error) bool -type WaitFunc func(try int) -type DeadlineFunc func() time.Time - -type ResilientTransport struct { - // Timeout is the maximum amount of time a dial will wait for - // a connect to complete. - // - // The default is no timeout. - // - // With or without a timeout, the operating system may impose - // its own earlier timeout. For instance, TCP timeouts are - // often around 3 minutes. - DialTimeout time.Duration - - // MaxTries, if non-zero, specifies the number of times we will retry on - // failure. Retries are only attempted for temporary network errors or known - // safe failures. - MaxTries int - Deadline DeadlineFunc - ShouldRetry RetryableFunc - Wait WaitFunc - transport *http.Transport -} - -// Convenience method for creating an http client -func NewClient(rt *ResilientTransport) *http.Client { - rt.transport = &http.Transport{ - Dial: func(netw, addr string) (net.Conn, error) { - c, err := net.DialTimeout(netw, addr, rt.DialTimeout) - if err != nil { - return nil, err - } - c.SetDeadline(rt.Deadline()) - return c, nil - }, - Proxy: http.ProxyFromEnvironment, - } - // TODO: Would be nice is ResilientTransport allowed clients to initialize - // with http.Transport attributes. - return &http.Client{ - Transport: rt, - } -} - -var retryingTransport = &ResilientTransport{ - Deadline: func() time.Time { - return time.Now().Add(5 * time.Second) - }, - DialTimeout: 10 * time.Second, - MaxTries: 3, - ShouldRetry: awsRetry, - Wait: ExpBackoff, -} - -// Exported default client -var RetryingClient = NewClient(retryingTransport) - -func (t *ResilientTransport) RoundTrip(req *http.Request) (*http.Response, error) { - return t.tries(req) -} - -// Retry a request a maximum of t.MaxTries times. -// We'll only retry if the proper criteria are met. -// If a wait function is specified, wait that amount of time -// In between requests. -func (t *ResilientTransport) tries(req *http.Request) (res *http.Response, err error) { - for try := 0; try < t.MaxTries; try += 1 { - res, err = t.transport.RoundTrip(req) - - if !t.ShouldRetry(req, res, err) { - break - } - if res != nil { - res.Body.Close() - } - if t.Wait != nil { - t.Wait(try) - } - } - - return -} - -func ExpBackoff(try int) { - time.Sleep(100 * time.Millisecond * - time.Duration(math.Exp2(float64(try)))) -} - -func LinearBackoff(try int) { - time.Sleep(time.Duration(try*100) * time.Millisecond) -} - -// Decide if we should retry a request. -// In general, the criteria for retrying a request is described here -// http://docs.aws.amazon.com/general/latest/gr/api-retries.html -func awsRetry(req *http.Request, res *http.Response, err error) bool { - retry := false - - // Retry if there's a temporary network error. - if neterr, ok := err.(net.Error); ok { - if neterr.Temporary() { - retry = true - } - } - - // Retry if we get a 5xx series error. - if res != nil { - if res.StatusCode >= 500 && res.StatusCode < 600 { - retry = true - } - } - - return retry -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/export_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/export_test.go deleted file mode 100644 index 5f4a9dd01..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/export_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package aws - -import ( - "net/http" - "time" -) - -// V4Signer: -// Exporting methods for testing - -func (s *V4Signer) RequestTime(req *http.Request) time.Time { - return s.requestTime(req) -} - -func (s *V4Signer) CanonicalRequest(req *http.Request) string { - return s.canonicalRequest(req, "") -} - -func (s *V4Signer) StringToSign(t time.Time, creq string) string { - return s.stringToSign(t, creq) -} - -func (s *V4Signer) Signature(t time.Time, sts string) string { - return s.signature(t, sts) -} - -func (s *V4Signer) Authorization(header http.Header, t time.Time, signature string) string { - return s.authorization(header, t, signature) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/regions.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/regions.go deleted file mode 100644 index 97e12e1dc..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/regions.go +++ /dev/null @@ -1,231 +0,0 @@ -package aws - -var USGovWest = Region{ - "us-gov-west-1", - "https://ec2.us-gov-west-1.amazonaws.com", - "https://s3-fips-us-gov-west-1.amazonaws.com", - "", - true, - true, - "", - "https://sns.us-gov-west-1.amazonaws.com", - "https://sqs.us-gov-west-1.amazonaws.com", - "", - "https://iam.us-gov.amazonaws.com", - "https://elasticloadbalancing.us-gov-west-1.amazonaws.com", - "https://dynamodb.us-gov-west-1.amazonaws.com", - ServiceInfo{"https://monitoring.us-gov-west-1.amazonaws.com", V2Signature}, - "https://autoscaling.us-gov-west-1.amazonaws.com", - ServiceInfo{"https://rds.us-gov-west-1.amazonaws.com", V2Signature}, - "", - "https://sts.amazonaws.com", - "https://cloudformation.us-gov-west-1.amazonaws.com", - "", -} - -var USEast = Region{ - "us-east-1", - "https://ec2.us-east-1.amazonaws.com", - "https://s3.amazonaws.com", - "", - false, - false, - "https://sdb.amazonaws.com", - "https://sns.us-east-1.amazonaws.com", - "https://sqs.us-east-1.amazonaws.com", - "https://email.us-east-1.amazonaws.com", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.us-east-1.amazonaws.com", - "https://dynamodb.us-east-1.amazonaws.com", - ServiceInfo{"https://monitoring.us-east-1.amazonaws.com", V2Signature}, - "https://autoscaling.us-east-1.amazonaws.com", - ServiceInfo{"https://rds.us-east-1.amazonaws.com", V2Signature}, - "https://kinesis.us-east-1.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.us-east-1.amazonaws.com", - "https://elasticache.us-east-1.amazonaws.com", -} - -var USWest = Region{ - "us-west-1", - "https://ec2.us-west-1.amazonaws.com", - "https://s3-us-west-1.amazonaws.com", - "", - true, - true, - "https://sdb.us-west-1.amazonaws.com", - "https://sns.us-west-1.amazonaws.com", - "https://sqs.us-west-1.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.us-west-1.amazonaws.com", - "https://dynamodb.us-west-1.amazonaws.com", - ServiceInfo{"https://monitoring.us-west-1.amazonaws.com", V2Signature}, - "https://autoscaling.us-west-1.amazonaws.com", - ServiceInfo{"https://rds.us-west-1.amazonaws.com", V2Signature}, - "", - "https://sts.amazonaws.com", - "https://cloudformation.us-west-1.amazonaws.com", - "https://elasticache.us-west-1.amazonaws.com", -} - -var USWest2 = Region{ - "us-west-2", - "https://ec2.us-west-2.amazonaws.com", - "https://s3-us-west-2.amazonaws.com", - "", - true, - true, - "https://sdb.us-west-2.amazonaws.com", - "https://sns.us-west-2.amazonaws.com", - "https://sqs.us-west-2.amazonaws.com", - "https://email.us-west-2.amazonaws.com", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.us-west-2.amazonaws.com", - "https://dynamodb.us-west-2.amazonaws.com", - ServiceInfo{"https://monitoring.us-west-2.amazonaws.com", V2Signature}, - "https://autoscaling.us-west-2.amazonaws.com", - ServiceInfo{"https://rds.us-west-2.amazonaws.com", V2Signature}, - "https://kinesis.us-west-2.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.us-west-2.amazonaws.com", - "https://elasticache.us-west-2.amazonaws.com", -} - -var EUWest = Region{ - "eu-west-1", - "https://ec2.eu-west-1.amazonaws.com", - "https://s3-eu-west-1.amazonaws.com", - "", - true, - true, - "https://sdb.eu-west-1.amazonaws.com", - "https://sns.eu-west-1.amazonaws.com", - "https://sqs.eu-west-1.amazonaws.com", - "https://email.eu-west-1.amazonaws.com", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.eu-west-1.amazonaws.com", - "https://dynamodb.eu-west-1.amazonaws.com", - ServiceInfo{"https://monitoring.eu-west-1.amazonaws.com", V2Signature}, - "https://autoscaling.eu-west-1.amazonaws.com", - ServiceInfo{"https://rds.eu-west-1.amazonaws.com", V2Signature}, - "https://kinesis.eu-west-1.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.eu-west-1.amazonaws.com", - "https://elasticache.eu-west-1.amazonaws.com", -} - -var EUCentral = Region{ - "eu-central-1", - "https://ec2.eu-central-1.amazonaws.com", - "https://s3-eu-central-1.amazonaws.com", - "", - true, - true, - "https://sdb.eu-central-1.amazonaws.com", - "https://sns.eu-central-1.amazonaws.com", - "https://sqs.eu-central-1.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.eu-central-1.amazonaws.com", - "https://dynamodb.eu-central-1.amazonaws.com", - ServiceInfo{"https://monitoring.eu-central-1.amazonaws.com", V2Signature}, - "https://autoscaling.eu-central-1.amazonaws.com", - ServiceInfo{"https://rds.eu-central-1.amazonaws.com", V2Signature}, - "https://kinesis.eu-central-1.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.eu-central-1.amazonaws.com", - "", -} - -var APSoutheast = Region{ - "ap-southeast-1", - "https://ec2.ap-southeast-1.amazonaws.com", - "https://s3-ap-southeast-1.amazonaws.com", - "", - true, - true, - "https://sdb.ap-southeast-1.amazonaws.com", - "https://sns.ap-southeast-1.amazonaws.com", - "https://sqs.ap-southeast-1.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.ap-southeast-1.amazonaws.com", - "https://dynamodb.ap-southeast-1.amazonaws.com", - ServiceInfo{"https://monitoring.ap-southeast-1.amazonaws.com", V2Signature}, - "https://autoscaling.ap-southeast-1.amazonaws.com", - ServiceInfo{"https://rds.ap-southeast-1.amazonaws.com", V2Signature}, - "https://kinesis.ap-southeast-1.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.ap-southeast-1.amazonaws.com", - "https://elasticache.ap-southeast-1.amazonaws.com", -} - -var APSoutheast2 = Region{ - "ap-southeast-2", - "https://ec2.ap-southeast-2.amazonaws.com", - "https://s3-ap-southeast-2.amazonaws.com", - "", - true, - true, - "https://sdb.ap-southeast-2.amazonaws.com", - "https://sns.ap-southeast-2.amazonaws.com", - "https://sqs.ap-southeast-2.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.ap-southeast-2.amazonaws.com", - "https://dynamodb.ap-southeast-2.amazonaws.com", - ServiceInfo{"https://monitoring.ap-southeast-2.amazonaws.com", V2Signature}, - "https://autoscaling.ap-southeast-2.amazonaws.com", - ServiceInfo{"https://rds.ap-southeast-2.amazonaws.com", V2Signature}, - "https://kinesis.ap-southeast-2.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.ap-southeast-2.amazonaws.com", - "https://elasticache.ap-southeast-2.amazonaws.com", -} - -var APNortheast = Region{ - "ap-northeast-1", - "https://ec2.ap-northeast-1.amazonaws.com", - "https://s3-ap-northeast-1.amazonaws.com", - "", - true, - true, - "https://sdb.ap-northeast-1.amazonaws.com", - "https://sns.ap-northeast-1.amazonaws.com", - "https://sqs.ap-northeast-1.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.ap-northeast-1.amazonaws.com", - "https://dynamodb.ap-northeast-1.amazonaws.com", - ServiceInfo{"https://monitoring.ap-northeast-1.amazonaws.com", V2Signature}, - "https://autoscaling.ap-northeast-1.amazonaws.com", - ServiceInfo{"https://rds.ap-northeast-1.amazonaws.com", V2Signature}, - "https://kinesis.ap-northeast-1.amazonaws.com", - "https://sts.amazonaws.com", - "https://cloudformation.ap-northeast-1.amazonaws.com", - "https://elasticache.ap-northeast-1.amazonaws.com", -} - -var SAEast = Region{ - "sa-east-1", - "https://ec2.sa-east-1.amazonaws.com", - "https://s3-sa-east-1.amazonaws.com", - "", - true, - true, - "https://sdb.sa-east-1.amazonaws.com", - "https://sns.sa-east-1.amazonaws.com", - "https://sqs.sa-east-1.amazonaws.com", - "", - "https://iam.amazonaws.com", - "https://elasticloadbalancing.sa-east-1.amazonaws.com", - "https://dynamodb.sa-east-1.amazonaws.com", - ServiceInfo{"https://monitoring.sa-east-1.amazonaws.com", V2Signature}, - "https://autoscaling.sa-east-1.amazonaws.com", - ServiceInfo{"https://rds.sa-east-1.amazonaws.com", V2Signature}, - "", - "https://sts.amazonaws.com", - "https://cloudformation.sa-east-1.amazonaws.com", - "https://elasticache.sa-east-1.amazonaws.com", -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry.go deleted file mode 100644 index bea964b9f..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry.go +++ /dev/null @@ -1,136 +0,0 @@ -package aws - -import ( - "math/rand" - "net" - "net/http" - "time" -) - -const ( - maxDelay = 20 * time.Second - defaultScale = 300 * time.Millisecond - throttlingScale = 500 * time.Millisecond - throttlingScaleRange = throttlingScale / 4 - defaultMaxRetries = 3 - dynamoDBScale = 25 * time.Millisecond - dynamoDBMaxRetries = 10 -) - -// A RetryPolicy encapsulates a strategy for implementing client retries. -// -// Default implementations are provided which match the AWS SDKs. -type RetryPolicy interface { - // ShouldRetry returns whether a client should retry a failed request. - ShouldRetry(target string, r *http.Response, err error, numRetries int) bool - - // Delay returns the time a client should wait before issuing a retry. - Delay(target string, r *http.Response, err error, numRetries int) time.Duration -} - -// DefaultRetryPolicy implements the AWS SDK default retry policy. -// -// It will retry up to 3 times, and uses an exponential backoff with a scale -// factor of 300ms (300ms, 600ms, 1200ms). If the retry is because of -// throttling, the delay will also include some randomness. -// -// See https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-core/src/main/java/com/amazonaws/retry/PredefinedRetryPolicies.java#L90. -type DefaultRetryPolicy struct { -} - -// ShouldRetry implements the RetryPolicy ShouldRetry method. -func (policy DefaultRetryPolicy) ShouldRetry(target string, r *http.Response, err error, numRetries int) bool { - return shouldRetry(r, err, numRetries, defaultMaxRetries) -} - -// Delay implements the RetryPolicy Delay method. -func (policy DefaultRetryPolicy) Delay(target string, r *http.Response, err error, numRetries int) time.Duration { - scale := defaultScale - if err, ok := err.(*Error); ok && isThrottlingException(err) { - scale = throttlingScale + time.Duration(rand.Int63n(int64(throttlingScaleRange))) - } - return exponentialBackoff(numRetries, scale) -} - -// DynamoDBRetryPolicy implements the AWS SDK DynamoDB retry policy. -// -// It will retry up to 10 times, and uses an exponential backoff with a scale -// factor of 25ms (25ms, 50ms, 100ms, ...). -// -// See https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-core/src/main/java/com/amazonaws/retry/PredefinedRetryPolicies.java#L103. -type DynamoDBRetryPolicy struct { -} - -// ShouldRetry implements the RetryPolicy ShouldRetry method. -func (policy DynamoDBRetryPolicy) ShouldRetry(target string, r *http.Response, err error, numRetries int) bool { - return shouldRetry(r, err, numRetries, dynamoDBMaxRetries) -} - -// Delay implements the RetryPolicy Delay method. -func (policy DynamoDBRetryPolicy) Delay(target string, r *http.Response, err error, numRetries int) time.Duration { - return exponentialBackoff(numRetries, dynamoDBScale) -} - -// NeverRetryPolicy never retries requests and returns immediately on failure. -type NeverRetryPolicy struct { -} - -// ShouldRetry implements the RetryPolicy ShouldRetry method. -func (policy NeverRetryPolicy) ShouldRetry(target string, r *http.Response, err error, numRetries int) bool { - return false -} - -// Delay implements the RetryPolicy Delay method. -func (policy NeverRetryPolicy) Delay(target string, r *http.Response, err error, numRetries int) time.Duration { - return time.Duration(0) -} - -// shouldRetry determines if we should retry the request. -// -// See http://docs.aws.amazon.com/general/latest/gr/api-retries.html. -func shouldRetry(r *http.Response, err error, numRetries int, maxRetries int) bool { - // Once we've exceeded the max retry attempts, game over. - if numRetries >= maxRetries { - return false - } - - // Always retry temporary network errors. - if err, ok := err.(net.Error); ok && err.Temporary() { - return true - } - - // Always retry 5xx responses. - if r != nil && r.StatusCode >= 500 { - return true - } - - // Always retry throttling exceptions. - if err, ok := err.(ServiceError); ok && isThrottlingException(err) { - return true - } - - // Other classes of failures indicate a problem with the request. Retrying - // won't help. - return false -} - -func exponentialBackoff(numRetries int, scale time.Duration) time.Duration { - if numRetries < 0 { - return time.Duration(0) - } - - delay := (1 << uint(numRetries)) * scale - if delay > maxDelay { - return maxDelay - } - return delay -} - -func isThrottlingException(err ServiceError) bool { - switch err.ErrorCode() { - case "Throttling", "ThrottlingException", "ProvisionedThroughputExceededException": - return true - default: - return false - } -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry_test.go deleted file mode 100644 index c1f10be4e..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/retry_test.go +++ /dev/null @@ -1,303 +0,0 @@ -package aws - -import ( - "math/rand" - "net" - "net/http" - "testing" - "time" -) - -type testInput struct { - res *http.Response - err error - numRetries int -} - -type testResult struct { - shouldRetry bool - delay time.Duration -} - -type testCase struct { - input testInput - defaultResult testResult - dynamoDBResult testResult -} - -var testCases = []testCase{ - // Test nil fields - testCase{ - input: testInput{ - err: nil, - res: nil, - numRetries: 0, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: 300 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: 25 * time.Millisecond, - }, - }, - // Test 3 different throttling exceptions - testCase{ - input: testInput{ - err: &Error{ - Code: "Throttling", - }, - numRetries: 0, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 617165505 * time.Nanosecond, // account for randomness with known seed - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 25 * time.Millisecond, - }, - }, - testCase{ - input: testInput{ - err: &Error{ - Code: "ThrottlingException", - }, - numRetries: 0, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 579393152 * time.Nanosecond, // account for randomness with known seed - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 25 * time.Millisecond, - }, - }, - testCase{ - input: testInput{ - err: &Error{ - Code: "ProvisionedThroughputExceededException", - }, - numRetries: 1, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 1105991654 * time.Nanosecond, // account for randomness with known seed - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 50 * time.Millisecond, - }, - }, - // Test a fake throttling exception - testCase{ - input: testInput{ - err: &Error{ - Code: "MyMadeUpThrottlingCode", - }, - numRetries: 0, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: 300 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: 25 * time.Millisecond, - }, - }, - // Test 5xx errors - testCase{ - input: testInput{ - res: &http.Response{ - StatusCode: http.StatusInternalServerError, - }, - numRetries: 1, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 600 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 50 * time.Millisecond, - }, - }, - testCase{ - input: testInput{ - res: &http.Response{ - StatusCode: http.StatusServiceUnavailable, - }, - numRetries: 1, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 600 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 50 * time.Millisecond, - }, - }, - // Test a random 400 error - testCase{ - input: testInput{ - res: &http.Response{ - StatusCode: http.StatusNotFound, - }, - numRetries: 1, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: 600 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: 50 * time.Millisecond, - }, - }, - // Test a temporary net.Error - testCase{ - input: testInput{ - res: &http.Response{}, - err: &net.DNSError{ - IsTimeout: true, - }, - numRetries: 2, - }, - defaultResult: testResult{ - shouldRetry: true, - delay: 1200 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 100 * time.Millisecond, - }, - }, - // Test a non-temporary net.Error - testCase{ - input: testInput{ - res: &http.Response{}, - err: &net.DNSError{ - IsTimeout: false, - }, - numRetries: 3, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: 2400 * time.Millisecond, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: 200 * time.Millisecond, - }, - }, - // Assert failure after hitting max default retries - testCase{ - input: testInput{ - err: &Error{ - Code: "ProvisionedThroughputExceededException", - }, - numRetries: defaultMaxRetries, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: 4313582352 * time.Nanosecond, // account for randomness with known seed - }, - dynamoDBResult: testResult{ - shouldRetry: true, - delay: 200 * time.Millisecond, - }, - }, - // Assert failure after hitting max DynamoDB retries - testCase{ - input: testInput{ - err: &Error{ - Code: "ProvisionedThroughputExceededException", - }, - numRetries: dynamoDBMaxRetries, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: maxDelay, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: maxDelay, - }, - }, - // Assert we never go over the maxDelay value - testCase{ - input: testInput{ - numRetries: 25, - }, - defaultResult: testResult{ - shouldRetry: false, - delay: maxDelay, - }, - dynamoDBResult: testResult{ - shouldRetry: false, - delay: maxDelay, - }, - }, -} - -func TestDefaultRetryPolicy(t *testing.T) { - rand.Seed(0) - var policy RetryPolicy - policy = &DefaultRetryPolicy{} - for _, test := range testCases { - res := test.input.res - err := test.input.err - numRetries := test.input.numRetries - - shouldRetry := policy.ShouldRetry("", res, err, numRetries) - if shouldRetry != test.defaultResult.shouldRetry { - t.Errorf("ShouldRetry returned %v, expected %v res=%#v err=%#v numRetries=%d", shouldRetry, test.defaultResult.shouldRetry, res, err, numRetries) - } - delay := policy.Delay("", res, err, numRetries) - if delay != test.defaultResult.delay { - t.Errorf("Delay returned %v, expected %v res=%#v err=%#v numRetries=%d", delay, test.defaultResult.delay, res, err, numRetries) - } - } -} - -func TestDynamoDBRetryPolicy(t *testing.T) { - var policy RetryPolicy - policy = &DynamoDBRetryPolicy{} - for _, test := range testCases { - res := test.input.res - err := test.input.err - numRetries := test.input.numRetries - - shouldRetry := policy.ShouldRetry("", res, err, numRetries) - if shouldRetry != test.dynamoDBResult.shouldRetry { - t.Errorf("ShouldRetry returned %v, expected %v res=%#v err=%#v numRetries=%d", shouldRetry, test.dynamoDBResult.shouldRetry, res, err, numRetries) - } - delay := policy.Delay("", res, err, numRetries) - if delay != test.dynamoDBResult.delay { - t.Errorf("Delay returned %v, expected %v res=%#v err=%#v numRetries=%d", delay, test.dynamoDBResult.delay, res, err, numRetries) - } - } -} - -func TestNeverRetryPolicy(t *testing.T) { - var policy RetryPolicy - policy = &NeverRetryPolicy{} - for _, test := range testCases { - res := test.input.res - err := test.input.err - numRetries := test.input.numRetries - - shouldRetry := policy.ShouldRetry("", res, err, numRetries) - if shouldRetry { - t.Errorf("ShouldRetry returned %v, expected %v res=%#v err=%#v numRetries=%d", shouldRetry, false, res, err, numRetries) - } - delay := policy.Delay("", res, err, numRetries) - if delay != time.Duration(0) { - t.Errorf("Delay returned %v, expected %v res=%#v err=%#v numRetries=%d", delay, time.Duration(0), res, err, numRetries) - } - } -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign.go deleted file mode 100644 index 20bcf0111..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign.go +++ /dev/null @@ -1,413 +0,0 @@ -package aws - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "path" - "sort" - "strings" - "time" -) - -type V2Signer struct { - auth Auth - service ServiceInfo - host string -} - -var b64 = base64.StdEncoding - -func NewV2Signer(auth Auth, service ServiceInfo) (*V2Signer, error) { - u, err := url.Parse(service.Endpoint) - if err != nil { - return nil, err - } - return &V2Signer{auth: auth, service: service, host: u.Host}, nil -} - -func (s *V2Signer) Sign(method, path string, params map[string]string) { - params["AWSAccessKeyId"] = s.auth.AccessKey - params["SignatureVersion"] = "2" - params["SignatureMethod"] = "HmacSHA256" - if s.auth.Token() != "" { - params["SecurityToken"] = s.auth.Token() - } - - // AWS specifies that the parameters in a signed request must - // be provided in the natural order of the keys. This is distinct - // from the natural order of the encoded value of key=value. - // Percent and gocheck.Equals affect the sorting order. - var keys, sarray []string - for k, _ := range params { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - sarray = append(sarray, Encode(k)+"="+Encode(params[k])) - } - joined := strings.Join(sarray, "&") - payload := method + "\n" + s.host + "\n" + path + "\n" + joined - hash := hmac.New(sha256.New, []byte(s.auth.SecretKey)) - hash.Write([]byte(payload)) - signature := make([]byte, b64.EncodedLen(hash.Size())) - b64.Encode(signature, hash.Sum(nil)) - - params["Signature"] = string(signature) -} - -// Common date formats for signing requests -const ( - ISO8601BasicFormat = "20060102T150405Z" - ISO8601BasicFormatShort = "20060102" -) - -type Route53Signer struct { - auth Auth -} - -func NewRoute53Signer(auth Auth) *Route53Signer { - return &Route53Signer{auth: auth} -} - -// getCurrentDate fetches the date stamp from the aws servers to -// ensure the auth headers are within 5 minutes of the server time -func (s *Route53Signer) getCurrentDate() string { - response, err := http.Get("https://route53.amazonaws.com/date") - if err != nil { - fmt.Print("Unable to get date from amazon: ", err) - return "" - } - - response.Body.Close() - return response.Header.Get("Date") -} - -// Creates the authorize signature based on the date stamp and secret key -func (s *Route53Signer) getHeaderAuthorize(message string) string { - hmacSha256 := hmac.New(sha256.New, []byte(s.auth.SecretKey)) - hmacSha256.Write([]byte(message)) - cryptedString := hmacSha256.Sum(nil) - - return base64.StdEncoding.EncodeToString(cryptedString) -} - -// Adds all the required headers for AWS Route53 API to the request -// including the authorization -func (s *Route53Signer) Sign(req *http.Request) { - date := s.getCurrentDate() - authHeader := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=%s,Signature=%s", - s.auth.AccessKey, "HmacSHA256", s.getHeaderAuthorize(date)) - - req.Header.Set("Host", req.Host) - req.Header.Set("X-Amzn-Authorization", authHeader) - req.Header.Set("X-Amz-Date", date) - req.Header.Set("Content-Type", "application/xml") - if s.auth.Token() != "" { - req.Header.Set("X-Amzn-Security-Token", s.auth.Token()) - } -} - -/* -The V4Signer encapsulates all of the functionality to sign a request with the AWS -Signature Version 4 Signing Process. (http://goo.gl/u1OWZz) -*/ -type V4Signer struct { - auth Auth - serviceName string - region Region - // Add the x-amz-content-sha256 header - IncludeXAmzContentSha256 bool -} - -/* -Return a new instance of a V4Signer capable of signing AWS requests. -*/ -func NewV4Signer(auth Auth, serviceName string, region Region) *V4Signer { - return &V4Signer{ - auth: auth, - serviceName: serviceName, - region: region, - IncludeXAmzContentSha256: false, - } -} - -/* -Sign a request according to the AWS Signature Version 4 Signing Process. (http://goo.gl/u1OWZz) - -The signed request will include an "x-amz-date" header with a current timestamp if a valid "x-amz-date" -or "date" header was not available in the original request. In addition, AWS Signature Version 4 requires -the "host" header to be a signed header, therefor the Sign method will manually set a "host" header from -the request.Host. - -The signed request will include a new "Authorization" header indicating that the request has been signed. - -Any changes to the request after signing the request will invalidate the signature. -*/ -func (s *V4Signer) Sign(req *http.Request) { - req.Header.Set("host", req.Host) // host header must be included as a signed header - t := s.requestTime(req) // Get request time - - payloadHash := "" - - if _, ok := req.Form["X-Amz-Expires"]; ok { - // We are authenticating the the request by using query params - // (also known as pre-signing a url, http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) - payloadHash = "UNSIGNED-PAYLOAD" - req.Header.Del("x-amz-date") - - req.Form["X-Amz-SignedHeaders"] = []string{s.signedHeaders(req.Header)} - req.Form["X-Amz-Algorithm"] = []string{"AWS4-HMAC-SHA256"} - req.Form["X-Amz-Credential"] = []string{s.auth.AccessKey + "/" + s.credentialScope(t)} - req.Form["X-Amz-Date"] = []string{t.Format(ISO8601BasicFormat)} - req.URL.RawQuery = req.Form.Encode() - } else { - payloadHash = s.payloadHash(req) - if s.IncludeXAmzContentSha256 { - req.Header.Set("x-amz-content-sha256", payloadHash) // x-amz-content-sha256 contains the payload hash - } - } - creq := s.canonicalRequest(req, payloadHash) // Build canonical request - sts := s.stringToSign(t, creq) // Build string to sign - signature := s.signature(t, sts) // Calculate the AWS Signature Version 4 - auth := s.authorization(req.Header, t, signature) // Create Authorization header value - - if _, ok := req.Form["X-Amz-Expires"]; ok { - req.Form["X-Amz-Signature"] = []string{signature} - } else { - req.Header.Set("Authorization", auth) // Add Authorization header to request - } - return -} - -/* -requestTime method will parse the time from the request "x-amz-date" or "date" headers. -If the "x-amz-date" header is present, that will take priority over the "date" header. -If neither header is defined or we are unable to parse either header as a valid date -then we will create a new "x-amz-date" header with the current time. -*/ -func (s *V4Signer) requestTime(req *http.Request) time.Time { - - // Get "x-amz-date" header - date := req.Header.Get("x-amz-date") - - // Attempt to parse as ISO8601BasicFormat - t, err := time.Parse(ISO8601BasicFormat, date) - if err == nil { - return t - } - - // Attempt to parse as http.TimeFormat - t, err = time.Parse(http.TimeFormat, date) - if err == nil { - req.Header.Set("x-amz-date", t.Format(ISO8601BasicFormat)) - return t - } - - // Get "date" header - date = req.Header.Get("date") - - // Attempt to parse as http.TimeFormat - t, err = time.Parse(http.TimeFormat, date) - if err == nil { - return t - } - - // Create a current time header to be used - t = time.Now().UTC() - req.Header.Set("x-amz-date", t.Format(ISO8601BasicFormat)) - return t -} - -/* -canonicalRequest method creates the canonical request according to Task 1 of the AWS Signature Version 4 Signing Process. (http://goo.gl/eUUZ3S) - - CanonicalRequest = - HTTPRequestMethod + '\n' + - CanonicalURI + '\n' + - CanonicalQueryString + '\n' + - CanonicalHeaders + '\n' + - SignedHeaders + '\n' + - HexEncode(Hash(Payload)) - -payloadHash is optional; use the empty string and it will be calculated from the request -*/ -func (s *V4Signer) canonicalRequest(req *http.Request, payloadHash string) string { - if payloadHash == "" { - payloadHash = s.payloadHash(req) - } - c := new(bytes.Buffer) - fmt.Fprintf(c, "%s\n", req.Method) - fmt.Fprintf(c, "%s\n", s.canonicalURI(req.URL)) - fmt.Fprintf(c, "%s\n", s.canonicalQueryString(req.URL)) - fmt.Fprintf(c, "%s\n\n", s.canonicalHeaders(req.Header)) - fmt.Fprintf(c, "%s\n", s.signedHeaders(req.Header)) - fmt.Fprintf(c, "%s", payloadHash) - return c.String() -} - -func (s *V4Signer) canonicalURI(u *url.URL) string { - u = &url.URL{Path: u.Path} - canonicalPath := u.String() - - slash := strings.HasSuffix(canonicalPath, "/") - canonicalPath = path.Clean(canonicalPath) - - if canonicalPath == "" || canonicalPath == "." { - canonicalPath = "/" - } - - if canonicalPath != "/" && slash { - canonicalPath += "/" - } - - return canonicalPath -} - -func (s *V4Signer) canonicalQueryString(u *url.URL) string { - var a []string - for k, vs := range u.Query() { - k = url.QueryEscape(k) - for _, v := range vs { - if v == "" { - a = append(a, k+"=") - } else { - v = url.QueryEscape(v) - a = append(a, k+"="+v) - } - } - } - sort.Strings(a) - return strings.Join(a, "&") -} - -func (s *V4Signer) canonicalHeaders(h http.Header) string { - i, a, lowerCase := 0, make([]string, len(h)), make(map[string][]string) - - for k, v := range h { - lowerCase[strings.ToLower(k)] = v - } - - var keys []string - for k := range lowerCase { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - v := lowerCase[k] - for j, w := range v { - v[j] = strings.Trim(w, " ") - } - sort.Strings(v) - a[i] = strings.ToLower(k) + ":" + strings.Join(v, ",") - i++ - } - return strings.Join(a, "\n") -} - -func (s *V4Signer) signedHeaders(h http.Header) string { - i, a := 0, make([]string, len(h)) - for k, _ := range h { - a[i] = strings.ToLower(k) - i++ - } - sort.Strings(a) - return strings.Join(a, ";") -} - -func (s *V4Signer) payloadHash(req *http.Request) string { - var b []byte - if req.Body == nil { - b = []byte("") - } else { - var err error - b, err = ioutil.ReadAll(req.Body) - if err != nil { - // TODO: I REALLY DON'T LIKE THIS PANIC!!!! - panic(err) - } - } - req.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - return s.hash(string(b)) -} - -/* -stringToSign method creates the string to sign accorting to Task 2 of the AWS Signature Version 4 Signing Process. (http://goo.gl/es1PAu) - - StringToSign = - Algorithm + '\n' + - RequestDate + '\n' + - CredentialScope + '\n' + - HexEncode(Hash(CanonicalRequest)) -*/ -func (s *V4Signer) stringToSign(t time.Time, creq string) string { - w := new(bytes.Buffer) - fmt.Fprint(w, "AWS4-HMAC-SHA256\n") - fmt.Fprintf(w, "%s\n", t.Format(ISO8601BasicFormat)) - fmt.Fprintf(w, "%s\n", s.credentialScope(t)) - fmt.Fprintf(w, "%s", s.hash(creq)) - return w.String() -} - -func (s *V4Signer) credentialScope(t time.Time) string { - return fmt.Sprintf("%s/%s/%s/aws4_request", t.Format(ISO8601BasicFormatShort), s.region.Name, s.serviceName) -} - -/* -signature method calculates the AWS Signature Version 4 according to Task 3 of the AWS Signature Version 4 Signing Process. (http://goo.gl/j0Yqe1) - - signature = HexEncode(HMAC(derived-signing-key, string-to-sign)) -*/ -func (s *V4Signer) signature(t time.Time, sts string) string { - h := s.hmac(s.derivedKey(t), []byte(sts)) - return fmt.Sprintf("%x", h) -} - -/* -derivedKey method derives a signing key to be used for signing a request. - - kSecret = Your AWS Secret Access Key - kDate = HMAC("AWS4" + kSecret, Date) - kRegion = HMAC(kDate, Region) - kService = HMAC(kRegion, Service) - kSigning = HMAC(kService, "aws4_request") -*/ -func (s *V4Signer) derivedKey(t time.Time) []byte { - h := s.hmac([]byte("AWS4"+s.auth.SecretKey), []byte(t.Format(ISO8601BasicFormatShort))) - h = s.hmac(h, []byte(s.region.Name)) - h = s.hmac(h, []byte(s.serviceName)) - h = s.hmac(h, []byte("aws4_request")) - return h -} - -/* -authorization method generates the authorization header value. -*/ -func (s *V4Signer) authorization(header http.Header, t time.Time, signature string) string { - w := new(bytes.Buffer) - fmt.Fprint(w, "AWS4-HMAC-SHA256 ") - fmt.Fprintf(w, "Credential=%s/%s, ", s.auth.AccessKey, s.credentialScope(t)) - fmt.Fprintf(w, "SignedHeaders=%s, ", s.signedHeaders(header)) - fmt.Fprintf(w, "Signature=%s", signature) - return w.String() -} - -// hash method calculates the sha256 hash for a given string -func (s *V4Signer) hash(in string) string { - h := sha256.New() - fmt.Fprintf(h, "%s", in) - return fmt.Sprintf("%x", h.Sum(nil)) -} - -// hmac method calculates the sha256 hmac for a given slice of bytes -func (s *V4Signer) hmac(key, data []byte) []byte { - h := hmac.New(sha256.New, key) - h.Write(data) - return h.Sum(nil) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign_test.go deleted file mode 100644 index 1c70c59d2..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/aws/sign_test.go +++ /dev/null @@ -1,569 +0,0 @@ -package aws_test - -import ( - "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "gopkg.in/check.v1" - "net/http" - "strings" - "time" -) - -var _ = check.Suite(&V4SignerSuite{}) - -type V4SignerSuite struct { - auth aws.Auth - region aws.Region - cases []V4SignerSuiteCase -} - -type V4SignerSuiteCase struct { - label string - request V4SignerSuiteCaseRequest - canonicalRequest string - stringToSign string - signature string - authorization string -} - -type V4SignerSuiteCaseRequest struct { - method string - host string - url string - headers []string - body string -} - -func (s *V4SignerSuite) SetUpSuite(c *check.C) { - s.auth = aws.Auth{AccessKey: "AKIDEXAMPLE", SecretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"} - s.region = aws.USEast - - // Test cases from the Signature Version 4 Test Suite (http://goo.gl/nguvs0) - s.cases = append(s.cases, - - // get-header-key-duplicate - V4SignerSuiteCase{ - label: "get-header-key-duplicate", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar", "zoo:foobar", "zoo:zoobar"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:foobar,zoobar,zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3c52f0eaae2b61329c0a332e3fa15842a37bc5812cf4d80eb64784308850e313", - signature: "54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed", - }, - - // get-header-value-order - V4SignerSuiteCase{ - label: "get-header-value-order", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p:z", "p:a", "p:p", "p:a"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:a,a,p,z\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n94c0389fefe0988cbbedc8606f0ca0b485b48da010d09fc844b45b697c8924fe", - signature: "d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d", - }, - - // get-header-value-trim - V4SignerSuiteCase{ - label: "get-header-value-trim", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p: phfft "}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:phfft\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndddd1902add08da1ac94782b05f9278c08dc7468db178a84f8950d93b30b1f35", - signature: "debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592", - }, - - // get-empty - V4SignerSuiteCase{ - label: "get-relative-relative", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-single-relative - V4SignerSuiteCase{ - label: "get-relative-relative", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/.", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-multiple-relative - V4SignerSuiteCase{ - label: "get-relative-relative", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/./././", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-relative-relative - V4SignerSuiteCase{ - label: "get-relative-relative", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/foo/bar/../..", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-relative - V4SignerSuiteCase{ - label: "get-relative", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/foo/..", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-slash-dot-slash - V4SignerSuiteCase{ - label: "get-slash-dot-slash", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/./", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-slash-pointless-dot - V4SignerSuiteCase{ - label: "get-slash-pointless-dot", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/./foo", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n8021a97572ee460f87ca67f4e8c0db763216d84715f5424a843a5312a3321e2d", - signature: "910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a", - }, - - // get-slash - V4SignerSuiteCase{ - label: "get-slash", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "//", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-slashes - V4SignerSuiteCase{ - label: "get-slashes", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "//foo//", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/foo/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n6bb4476ee8745730c9cb79f33a0c70baa6d8af29c0077fa12e4e8f1dd17e7098", - signature: "b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19", - }, - - // get-space - V4SignerSuiteCase{ - label: "get-space", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/%20/foo", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/%20/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n69c45fb9fe3fd76442b5086e50b2e9fec8298358da957b293ef26e506fdfb54b", - signature: "f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374", - }, - - // get-unreserved - V4SignerSuiteCase{ - label: "get-unreserved", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndf63ee3247c0356c696a3b21f8d8490b01fa9cd5bc6550ef5ef5f4636b7b8901", - signature: "830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e", - }, - - // get-utf8 - V4SignerSuiteCase{ - label: "get-utf8", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/%E1%88%B4", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/%E1%88%B4\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n27ba31df5dbc6e063d8f87d62eb07143f7f271c5330a917840586ac1c85b6f6b", - signature: "8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74", - }, - - // get-vanilla-empty-query-key - V4SignerSuiteCase{ - label: "get-vanilla-empty-query-key", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?foo=bar", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n0846c2945b0832deb7a463c66af5c4f8bd54ec28c438e67a214445b157c9ddf8", - signature: "56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f", - }, - - // get-vanilla-query-order-key-case - V4SignerSuiteCase{ - label: "get-vanilla-query-order-key-case", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?foo=Zoo&foo=aha", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\nfoo=Zoo&foo=aha\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ne25f777ba161a0f1baf778a87faf057187cf5987f17953320e3ca399feb5f00d", - signature: "be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09", - }, - - // get-vanilla-query-order-key - V4SignerSuiteCase{ - label: "get-vanilla-query-order-key", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?a=foo&b=foo", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\na=foo&b=foo\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n2f23d14fe13caebf6dfda346285c6d9c14f49eaca8f5ec55c627dd7404f7a727", - signature: "0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b", - }, - - // get-vanilla-query-order-value - V4SignerSuiteCase{ - label: "get-vanilla-query-order-value", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?foo=b&foo=a", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\nfoo=a&foo=b\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n33dffc220e89131f8f6157a35c40903daa658608d9129ff9489e5cf5bbd9b11b", - signature: "feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc", - }, - - // get-vanilla-query-unreserved - V4SignerSuiteCase{ - label: "get-vanilla-query-unreserved", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nd2578f3156d4c9d180713d1ff20601d8a3eed0dd35447d24603d7d67414bd6b5", - signature: "f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb", - }, - - // get-vanilla-query - V4SignerSuiteCase{ - label: "get-vanilla-query", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // get-vanilla-ut8-query - V4SignerSuiteCase{ - label: "get-vanilla-ut8-query", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/?ሴ=bar", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n%E1%88%B4=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nde5065ff39c131e6c2e2bd19cd9345a794bf3b561eab20b8d97b2093fc2a979e", - signature: "6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c", - }, - - // get-vanilla - V4SignerSuiteCase{ - label: "get-vanilla", - request: V4SignerSuiteCaseRequest{ - method: "GET", - host: "host.foo.com", - url: "/", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1", - signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470", - }, - - // post-header-key-case - V4SignerSuiteCase{ - label: "post-header-key-case", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4", - signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726", - }, - - // post-header-key-sort - V4SignerSuiteCase{ - label: "post-header-key-sort", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n34e1bddeb99e76ee01d63b5e28656111e210529efeec6cdfd46a48e4c734545d", - signature: "b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a", - }, - - // post-header-value-case - V4SignerSuiteCase{ - label: "post-header-value-case", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "zoo:ZOOBAR"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:ZOOBAR\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3aae6d8274b8c03e2cc96fc7d6bda4b9bd7a0a184309344470b2c96953e124aa", - signature: "273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7", - }, - - // post-vanilla-empty-query-value - V4SignerSuiteCase{ - label: "post-vanilla-empty-query-value", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/?foo=bar", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e", - signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92", - }, - - // post-vanilla-query - V4SignerSuiteCase{ - label: "post-vanilla-query", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/?foo=bar", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e", - signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92", - }, - - // post-vanilla - V4SignerSuiteCase{ - label: "post-vanilla", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - }, - canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4", - signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726", - }, - - // post-x-www-form-urlencoded-parameters - V4SignerSuiteCase{ - label: "post-x-www-form-urlencoded-parameters", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"Content-Type:application/x-www-form-urlencoded; charset=utf8", "Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - body: "foo=bar", - }, - canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded; charset=utf8\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nc4115f9e54b5cecf192b1eaa23b8e88ed8dc5391bd4fde7b3fff3d9c9fe0af1f", - signature: "b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71", - }, - - // post-x-www-form-urlencoded - V4SignerSuiteCase{ - label: "post-x-www-form-urlencoded", - request: V4SignerSuiteCaseRequest{ - method: "POST", - host: "host.foo.com", - url: "/", - headers: []string{"Content-Type:application/x-www-form-urlencoded", "Date:Mon, 09 Sep 2011 23:36:00 GMT"}, - body: "foo=bar", - }, - canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a", - stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n4c5c6e4b52fb5fb947a8733982a8a5a61b14f04345cbfe6e739236c76dd48f74", - signature: "5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc", - authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc", - }, - ) -} - -func (s *V4SignerSuite) TestCases(c *check.C) { - signer := aws.NewV4Signer(s.auth, "host", s.region) - - for _, testCase := range s.cases { - - req, err := http.NewRequest(testCase.request.method, "http://"+testCase.request.host+testCase.request.url, strings.NewReader(testCase.request.body)) - c.Assert(err, check.IsNil, check.Commentf("Testcase: %s", testCase.label)) - for _, v := range testCase.request.headers { - h := strings.SplitN(v, ":", 2) - req.Header.Add(h[0], h[1]) - } - req.Header.Set("host", req.Host) - - t := signer.RequestTime(req) - - canonicalRequest := signer.CanonicalRequest(req) - c.Check(canonicalRequest, check.Equals, testCase.canonicalRequest, check.Commentf("Testcase: %s", testCase.label)) - - stringToSign := signer.StringToSign(t, canonicalRequest) - c.Check(stringToSign, check.Equals, testCase.stringToSign, check.Commentf("Testcase: %s", testCase.label)) - - signature := signer.Signature(t, stringToSign) - c.Check(signature, check.Equals, testCase.signature, check.Commentf("Testcase: %s", testCase.label)) - - authorization := signer.Authorization(req.Header, t, signature) - c.Check(authorization, check.Equals, testCase.authorization, check.Commentf("Testcase: %s", testCase.label)) - - signer.Sign(req) - c.Check(req.Header.Get("Authorization"), check.Equals, testCase.authorization, check.Commentf("Testcase: %s", testCase.label)) - } -} - -func ExampleV4Signer() { - // Get auth from env vars - auth, err := aws.EnvAuth() - if err != nil { - fmt.Println(err) - } - - // Create a signer with the auth, name of the service, and aws region - signer := aws.NewV4Signer(auth, "dynamodb", aws.USEast) - - // Create a request - req, err := http.NewRequest("POST", aws.USEast.DynamoDBEndpoint, strings.NewReader("sample_request")) - if err != nil { - fmt.Println(err) - } - - // Date or x-amz-date header is required to sign a request - req.Header.Add("Date", time.Now().UTC().Format(http.TimeFormat)) - - // Sign the request - signer.Sign(req) - - // Issue signed request - http.DefaultClient.Do(req) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/export_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/export_test.go deleted file mode 100644 index cd826b54e..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/export_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package s3 - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" -) - -var originalStrategy = attempts - -func SetAttemptStrategy(s *aws.AttemptStrategy) { - if s == nil { - attempts = originalStrategy - } else { - attempts = *s - } -} - -func Sign(auth aws.Auth, method, path string, params, headers map[string][]string) { - sign(auth, method, path, params, headers) -} - -func SetListPartsMax(n int) { - listPartsMax = n -} - -func SetListMultiMax(n int) { - listMultiMax = n -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle.go deleted file mode 100644 index d9281261b..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle.go +++ /dev/null @@ -1,202 +0,0 @@ -package s3 - -import ( - "crypto/md5" - "encoding/base64" - "encoding/xml" - "net/url" - "strconv" - "time" -) - -// Implements an interface for s3 bucket lifecycle configuration -// See goo.gl/d0bbDf for details. - -const ( - LifecycleRuleStatusEnabled = "Enabled" - LifecycleRuleStatusDisabled = "Disabled" - LifecycleRuleDateFormat = "2006-01-02" - StorageClassGlacier = "GLACIER" -) - -type Expiration struct { - Days *uint `xml:"Days,omitempty"` - Date string `xml:"Date,omitempty"` -} - -// Returns Date as a time.Time. -func (r *Expiration) ParseDate() (time.Time, error) { - return time.Parse(LifecycleRuleDateFormat, r.Date) -} - -type Transition struct { - Days *uint `xml:"Days,omitempty"` - Date string `xml:"Date,omitempty"` - StorageClass string `xml:"StorageClass"` -} - -// Returns Date as a time.Time. -func (r *Transition) ParseDate() (time.Time, error) { - return time.Parse(LifecycleRuleDateFormat, r.Date) -} - -type NoncurrentVersionExpiration struct { - Days *uint `xml:"NoncurrentDays,omitempty"` -} - -type NoncurrentVersionTransition struct { - Days *uint `xml:"NoncurrentDays,omitempty"` - StorageClass string `xml:"StorageClass"` -} - -type LifecycleRule struct { - ID string `xml:"ID"` - Prefix string `xml:"Prefix"` - Status string `xml:"Status"` - NoncurrentVersionTransition *NoncurrentVersionTransition `xml:"NoncurrentVersionTransition,omitempty"` - NoncurrentVersionExpiration *NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty"` - Transition *Transition `xml:"Transition,omitempty"` - Expiration *Expiration `xml:"Expiration,omitempty"` -} - -// Create a lifecycle rule with arbitrary identifier id and object name prefix -// for which the rules should apply. -func NewLifecycleRule(id, prefix string) *LifecycleRule { - rule := &LifecycleRule{ - ID: id, - Prefix: prefix, - Status: LifecycleRuleStatusEnabled, - } - return rule -} - -// Adds a transition rule in days. Overwrites any previous transition rule. -func (r *LifecycleRule) SetTransitionDays(days uint) { - r.Transition = &Transition{ - Days: &days, - StorageClass: StorageClassGlacier, - } -} - -// Adds a transition rule as a date. Overwrites any previous transition rule. -func (r *LifecycleRule) SetTransitionDate(date time.Time) { - r.Transition = &Transition{ - Date: date.Format(LifecycleRuleDateFormat), - StorageClass: StorageClassGlacier, - } -} - -// Adds an expiration rule in days. Overwrites any previous expiration rule. -// Days must be > 0. -func (r *LifecycleRule) SetExpirationDays(days uint) { - r.Expiration = &Expiration{ - Days: &days, - } -} - -// Adds an expiration rule as a date. Overwrites any previous expiration rule. -func (r *LifecycleRule) SetExpirationDate(date time.Time) { - r.Expiration = &Expiration{ - Date: date.Format(LifecycleRuleDateFormat), - } -} - -// Adds a noncurrent version transition rule. Overwrites any previous -// noncurrent version transition rule. -func (r *LifecycleRule) SetNoncurrentVersionTransitionDays(days uint) { - r.NoncurrentVersionTransition = &NoncurrentVersionTransition{ - Days: &days, - StorageClass: StorageClassGlacier, - } -} - -// Adds a noncurrent version expiration rule. Days must be > 0. Overwrites -// any previous noncurrent version expiration rule. -func (r *LifecycleRule) SetNoncurrentVersionExpirationDays(days uint) { - r.NoncurrentVersionExpiration = &NoncurrentVersionExpiration{ - Days: &days, - } -} - -// Marks the rule as disabled. -func (r *LifecycleRule) Disable() { - r.Status = LifecycleRuleStatusDisabled -} - -// Marks the rule as enabled (default). -func (r *LifecycleRule) Enable() { - r.Status = LifecycleRuleStatusEnabled -} - -type LifecycleConfiguration struct { - XMLName xml.Name `xml:"LifecycleConfiguration"` - Rules *[]*LifecycleRule `xml:"Rule,omitempty"` -} - -// Adds a LifecycleRule to the configuration. -func (c *LifecycleConfiguration) AddRule(r *LifecycleRule) { - var rules []*LifecycleRule - if c.Rules != nil { - rules = *c.Rules - } - rules = append(rules, r) - c.Rules = &rules -} - -// Sets the bucket's lifecycle configuration. -func (b *Bucket) PutLifecycleConfiguration(c *LifecycleConfiguration) error { - doc, err := xml.Marshal(c) - if err != nil { - return err - } - - buf := makeXmlBuffer(doc) - digest := md5.New() - size, err := digest.Write(buf.Bytes()) - if err != nil { - return err - } - - headers := map[string][]string{ - "Content-Length": {strconv.FormatInt(int64(size), 10)}, - "Content-MD5": {base64.StdEncoding.EncodeToString(digest.Sum(nil))}, - } - - req := &request{ - path: "/", - method: "PUT", - bucket: b.Name, - headers: headers, - payload: buf, - params: url.Values{"lifecycle": {""}}, - } - - return b.S3.queryV4Sign(req, nil) -} - -// Retrieves the lifecycle configuration for the bucket. AWS returns an error -// if no lifecycle found. -func (b *Bucket) GetLifecycleConfiguration() (*LifecycleConfiguration, error) { - req := &request{ - method: "GET", - bucket: b.Name, - path: "/", - params: url.Values{"lifecycle": {""}}, - } - - conf := &LifecycleConfiguration{} - err := b.S3.queryV4Sign(req, conf) - return conf, err -} - -// Delete the bucket's lifecycle configuration. -func (b *Bucket) DeleteLifecycleConfiguration() error { - req := &request{ - method: "DELETE", - bucket: b.Name, - path: "/", - params: url.Values{"lifecycle": {""}}, - } - - return b.S3.queryV4Sign(req, nil) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle_test.go deleted file mode 100644 index 269156dca..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/lifecycle_test.go +++ /dev/null @@ -1,205 +0,0 @@ -package s3_test - -import ( - "encoding/xml" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "gopkg.in/check.v1" - "io/ioutil" - "net/http" - "strings" - "time" -) - -func (s *S) TestLifecycleConfiguration(c *check.C) { - date, err := time.Parse(s3.LifecycleRuleDateFormat, "2014-09-10") - c.Check(err, check.IsNil) - - conf := &s3.LifecycleConfiguration{} - - rule := s3.NewLifecycleRule("transition-days", "/") - rule.SetTransitionDays(7) - conf.AddRule(rule) - - rule = s3.NewLifecycleRule("transition-date", "/") - rule.SetTransitionDate(date) - conf.AddRule(rule) - - rule = s3.NewLifecycleRule("expiration-days", "") - rule.SetExpirationDays(1) - conf.AddRule(rule) - - rule = s3.NewLifecycleRule("expiration-date", "") - rule.SetExpirationDate(date) - conf.AddRule(rule) - - rule = s3.NewLifecycleRule("noncurrent-transition", "") - rule.SetNoncurrentVersionTransitionDays(11) - conf.AddRule(rule) - - rule = s3.NewLifecycleRule("noncurrent-expiration", "") - rule.SetNoncurrentVersionExpirationDays(1011) - - // Test Disable() and Enable() toggling - c.Check(rule.Status, check.Equals, s3.LifecycleRuleStatusEnabled) - rule.Disable() - c.Check(rule.Status, check.Equals, s3.LifecycleRuleStatusDisabled) - rule.Enable() - c.Check(rule.Status, check.Equals, s3.LifecycleRuleStatusEnabled) - rule.Disable() - c.Check(rule.Status, check.Equals, s3.LifecycleRuleStatusDisabled) - - conf.AddRule(rule) - - doc, err := xml.MarshalIndent(conf, "", " ") - c.Check(err, check.IsNil) - - expectedDoc := ` - - transition-days - / - Enabled - - 7 - GLACIER - - - - transition-date - / - Enabled - - 2014-09-10 - GLACIER - - - - expiration-days - - Enabled - - 1 - - - - expiration-date - - Enabled - - 2014-09-10 - - - - noncurrent-transition - - Enabled - - 11 - GLACIER - - - - noncurrent-expiration - - Disabled - - 1011 - - -` - - c.Check(string(doc), check.Equals, expectedDoc) - - // Unmarshalling test - conf2 := &s3.LifecycleConfiguration{} - err = xml.Unmarshal(doc, conf2) - c.Check(err, check.IsNil) - s.checkLifecycleConfigurationEqual(c, conf, conf2) -} - -func (s *S) checkLifecycleConfigurationEqual(c *check.C, conf, conf2 *s3.LifecycleConfiguration) { - c.Check(len(*conf2.Rules), check.Equals, len(*conf.Rules)) - for i, rule := range *conf2.Rules { - confRules := *conf.Rules - c.Check(rule, check.DeepEquals, confRules[i]) - } -} - -func (s *S) checkLifecycleRequest(c *check.C, req *http.Request) { - // ?lifecycle= is the only query param - v, ok := req.Form["lifecycle"] - c.Assert(ok, check.Equals, true) - c.Assert(v, check.HasLen, 1) - c.Assert(v[0], check.Equals, "") - - c.Assert(req.Header["X-Amz-Date"], check.HasLen, 1) - c.Assert(req.Header["X-Amz-Date"][0], check.Not(check.Equals), "") - - // Lifecycle methods require V4 auth - usesV4 := strings.HasPrefix(req.Header["Authorization"][0], "AWS4-HMAC-SHA256") - c.Assert(usesV4, check.Equals, true) -} - -func (s *S) TestPutLifecycleConfiguration(c *check.C) { - testServer.Response(200, nil, "") - - conf := &s3.LifecycleConfiguration{} - rule := s3.NewLifecycleRule("id", "") - rule.SetTransitionDays(7) - conf.AddRule(rule) - - doc, err := xml.Marshal(conf) - c.Check(err, check.IsNil) - - b := s.s3.Bucket("bucket") - err = b.PutLifecycleConfiguration(conf) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - c.Assert(req.Header["Content-Md5"], check.HasLen, 1) - c.Assert(req.Header["Content-Md5"][0], check.Not(check.Equals), "") - s.checkLifecycleRequest(c, req) - - // Check we sent the correct xml serialization - data, err := ioutil.ReadAll(req.Body) - req.Body.Close() - c.Assert(err, check.IsNil) - header := "\n" - c.Assert(string(data), check.Equals, header+string(doc)) -} - -func (s *S) TestGetLifecycleConfiguration(c *check.C) { - conf := &s3.LifecycleConfiguration{} - rule := s3.NewLifecycleRule("id", "") - rule.SetTransitionDays(7) - conf.AddRule(rule) - - doc, err := xml.Marshal(conf) - c.Check(err, check.IsNil) - - testServer.Response(200, nil, string(doc)) - - b := s.s3.Bucket("bucket") - conf2, err := b.GetLifecycleConfiguration() - c.Check(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - s.checkLifecycleRequest(c, req) - s.checkLifecycleConfigurationEqual(c, conf, conf2) -} - -func (s *S) TestDeleteLifecycleConfiguration(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - err := b.DeleteLifecycleConfiguration() - c.Check(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "DELETE") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - s.checkLifecycleRequest(c, req) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi.go deleted file mode 100644 index 80f17cbee..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi.go +++ /dev/null @@ -1,464 +0,0 @@ -package s3 - -import ( - "bytes" - "crypto/md5" - "encoding/base64" - "encoding/hex" - "encoding/xml" - "errors" - "io" - "net/url" - "sort" - "strconv" - "strings" -) - -// Multi represents an unfinished multipart upload. -// -// Multipart uploads allow sending big objects in smaller chunks. -// After all parts have been sent, the upload must be explicitly -// completed by calling Complete with the list of parts. -// -// See http://goo.gl/vJfTG for an overview of multipart uploads. -type Multi struct { - Bucket *Bucket - Key string - UploadId string -} - -// That's the default. Here just for testing. -var listMultiMax = 1000 - -type listMultiResp struct { - NextKeyMarker string - NextUploadIdMarker string - IsTruncated bool - Upload []Multi - CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` -} - -// ListMulti returns the list of unfinished multipart uploads in b. -// -// The prefix parameter limits the response to keys that begin with the -// specified prefix. You can use prefixes to separate a bucket into different -// groupings of keys (to get the feeling of folders, for example). -// -// The delim parameter causes the response to group all of the keys that -// share a common prefix up to the next delimiter in a single entry within -// the CommonPrefixes field. You can use delimiters to separate a bucket -// into different groupings of keys, similar to how folders would work. -// -// See http://goo.gl/ePioY for details. -func (b *Bucket) ListMulti(prefix, delim string) (multis []*Multi, prefixes []string, err error) { - params := map[string][]string{ - "uploads": {""}, - "max-uploads": {strconv.FormatInt(int64(listMultiMax), 10)}, - "prefix": {prefix}, - "delimiter": {delim}, - } - for attempt := attempts.Start(); attempt.Next(); { - req := &request{ - method: "GET", - bucket: b.Name, - params: params, - } - var resp listMultiResp - err := b.S3.query(req, &resp) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return nil, nil, err - } - for i := range resp.Upload { - multi := &resp.Upload[i] - multi.Bucket = b - multis = append(multis, multi) - } - prefixes = append(prefixes, resp.CommonPrefixes...) - if !resp.IsTruncated { - return multis, prefixes, nil - } - params["key-marker"] = []string{resp.NextKeyMarker} - params["upload-id-marker"] = []string{resp.NextUploadIdMarker} - attempt = attempts.Start() // Last request worked. - } - panic("unreachable") -} - -// Multi returns a multipart upload handler for the provided key -// inside b. If a multipart upload exists for key, it is returned, -// otherwise a new multipart upload is initiated with contType and perm. -func (b *Bucket) Multi(key, contType string, perm ACL, options Options) (*Multi, error) { - multis, _, err := b.ListMulti(key, "") - if err != nil && !hasCode(err, "NoSuchUpload") { - return nil, err - } - for _, m := range multis { - if m.Key == key { - return m, nil - } - } - return b.InitMulti(key, contType, perm, options) -} - -// InitMulti initializes a new multipart upload at the provided -// key inside b and returns a value for manipulating it. -// -// See http://goo.gl/XP8kL for details. -func (b *Bucket) InitMulti(key string, contType string, perm ACL, options Options) (*Multi, error) { - headers := map[string][]string{ - "Content-Type": {contType}, - "Content-Length": {"0"}, - "x-amz-acl": {string(perm)}, - } - options.addHeaders(headers) - params := map[string][]string{ - "uploads": {""}, - } - req := &request{ - method: "POST", - bucket: b.Name, - path: key, - headers: headers, - params: params, - } - var err error - var resp struct { - UploadId string `xml:"UploadId"` - } - for attempt := attempts.Start(); attempt.Next(); { - err = b.S3.query(req, &resp) - if !shouldRetry(err) { - break - } - } - if err != nil { - return nil, err - } - return &Multi{Bucket: b, Key: key, UploadId: resp.UploadId}, nil -} - -func (m *Multi) PutPartCopy(n int, options CopyOptions, source string) (*CopyObjectResult, Part, error) { - headers := map[string][]string{ - "x-amz-copy-source": {url.QueryEscape(source)}, - } - options.addHeaders(headers) - params := map[string][]string{ - "uploadId": {m.UploadId}, - "partNumber": {strconv.FormatInt(int64(n), 10)}, - } - - sourceBucket := m.Bucket.S3.Bucket(strings.TrimRight(strings.SplitAfterN(source, "/", 2)[0], "/")) - sourceMeta, err := sourceBucket.Head(strings.SplitAfterN(source, "/", 2)[1], nil) - if err != nil { - return nil, Part{}, err - } - - for attempt := attempts.Start(); attempt.Next(); { - req := &request{ - method: "PUT", - bucket: m.Bucket.Name, - path: m.Key, - headers: headers, - params: params, - } - resp := &CopyObjectResult{} - err = m.Bucket.S3.query(req, resp) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return nil, Part{}, err - } - if resp.ETag == "" { - return nil, Part{}, errors.New("part upload succeeded with no ETag") - } - return resp, Part{n, resp.ETag, sourceMeta.ContentLength}, nil - } - panic("unreachable") -} - -// PutPart sends part n of the multipart upload, reading all the content from r. -// Each part, except for the last one, must be at least 5MB in size. -// -// See http://goo.gl/pqZer for details. -func (m *Multi) PutPart(n int, r io.ReadSeeker) (Part, error) { - partSize, _, md5b64, err := seekerInfo(r) - if err != nil { - return Part{}, err - } - return m.putPart(n, r, partSize, md5b64) -} - -func (m *Multi) putPart(n int, r io.ReadSeeker, partSize int64, md5b64 string) (Part, error) { - headers := map[string][]string{ - "Content-Length": {strconv.FormatInt(partSize, 10)}, - "Content-MD5": {md5b64}, - } - params := map[string][]string{ - "uploadId": {m.UploadId}, - "partNumber": {strconv.FormatInt(int64(n), 10)}, - } - for attempt := attempts.Start(); attempt.Next(); { - _, err := r.Seek(0, 0) - if err != nil { - return Part{}, err - } - req := &request{ - method: "PUT", - bucket: m.Bucket.Name, - path: m.Key, - headers: headers, - params: params, - payload: r, - } - err = m.Bucket.S3.prepare(req) - if err != nil { - return Part{}, err - } - resp, err := m.Bucket.S3.run(req, nil) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return Part{}, err - } - etag := resp.Header.Get("ETag") - if etag == "" { - return Part{}, errors.New("part upload succeeded with no ETag") - } - return Part{n, etag, partSize}, nil - } - panic("unreachable") -} - -func seekerInfo(r io.ReadSeeker) (size int64, md5hex string, md5b64 string, err error) { - _, err = r.Seek(0, 0) - if err != nil { - return 0, "", "", err - } - digest := md5.New() - size, err = io.Copy(digest, r) - if err != nil { - return 0, "", "", err - } - sum := digest.Sum(nil) - md5hex = hex.EncodeToString(sum) - md5b64 = base64.StdEncoding.EncodeToString(sum) - return size, md5hex, md5b64, nil -} - -type Part struct { - N int `xml:"PartNumber"` - ETag string - Size int64 -} - -type partSlice []Part - -func (s partSlice) Len() int { return len(s) } -func (s partSlice) Less(i, j int) bool { return s[i].N < s[j].N } -func (s partSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -type listPartsResp struct { - NextPartNumberMarker string - IsTruncated bool - Part []Part -} - -// That's the default. Here just for testing. -var listPartsMax = 1000 - -// Kept for backcompatability. See the documentation for ListPartsFull -func (m *Multi) ListParts() ([]Part, error) { - return m.ListPartsFull(0, listPartsMax) -} - -// ListParts returns the list of previously uploaded parts in m, -// ordered by part number (Only parts with higher part numbers than -// partNumberMarker will be listed). Only up to maxParts parts will be -// returned. -// -// See http://goo.gl/ePioY for details. -func (m *Multi) ListPartsFull(partNumberMarker int, maxParts int) ([]Part, error) { - if maxParts > listPartsMax { - maxParts = listPartsMax - } - - params := map[string][]string{ - "uploadId": {m.UploadId}, - "max-parts": {strconv.FormatInt(int64(maxParts), 10)}, - "part-number-marker": {strconv.FormatInt(int64(partNumberMarker), 10)}, - } - var parts partSlice - for attempt := attempts.Start(); attempt.Next(); { - req := &request{ - method: "GET", - bucket: m.Bucket.Name, - path: m.Key, - params: params, - } - var resp listPartsResp - err := m.Bucket.S3.query(req, &resp) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return nil, err - } - parts = append(parts, resp.Part...) - if !resp.IsTruncated { - sort.Sort(parts) - return parts, nil - } - params["part-number-marker"] = []string{resp.NextPartNumberMarker} - attempt = attempts.Start() // Last request worked. - } - panic("unreachable") -} - -type ReaderAtSeeker interface { - io.ReaderAt - io.ReadSeeker -} - -// PutAll sends all of r via a multipart upload with parts no larger -// than partSize bytes, which must be set to at least 5MB. -// Parts previously uploaded are either reused if their checksum -// and size match the new part, or otherwise overwritten with the -// new content. -// PutAll returns all the parts of m (reused or not). -func (m *Multi) PutAll(r ReaderAtSeeker, partSize int64) ([]Part, error) { - old, err := m.ListParts() - if err != nil && !hasCode(err, "NoSuchUpload") { - return nil, err - } - reuse := 0 // Index of next old part to consider reusing. - current := 1 // Part number of latest good part handled. - totalSize, err := r.Seek(0, 2) - if err != nil { - return nil, err - } - first := true // Must send at least one empty part if the file is empty. - var result []Part -NextSection: - for offset := int64(0); offset < totalSize || first; offset += partSize { - first = false - if offset+partSize > totalSize { - partSize = totalSize - offset - } - section := io.NewSectionReader(r, offset, partSize) - _, md5hex, md5b64, err := seekerInfo(section) - if err != nil { - return nil, err - } - for reuse < len(old) && old[reuse].N <= current { - // Looks like this part was already sent. - part := &old[reuse] - etag := `"` + md5hex + `"` - if part.N == current && part.Size == partSize && part.ETag == etag { - // Checksum matches. Reuse the old part. - result = append(result, *part) - current++ - continue NextSection - } - reuse++ - } - - // Part wasn't found or doesn't match. Send it. - part, err := m.putPart(current, section, partSize, md5b64) - if err != nil { - return nil, err - } - result = append(result, part) - current++ - } - return result, nil -} - -type completeUpload struct { - XMLName xml.Name `xml:"CompleteMultipartUpload"` - Parts completeParts `xml:"Part"` -} - -type completePart struct { - PartNumber int - ETag string -} - -type completeParts []completePart - -func (p completeParts) Len() int { return len(p) } -func (p completeParts) Less(i, j int) bool { return p[i].PartNumber < p[j].PartNumber } -func (p completeParts) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -// Complete assembles the given previously uploaded parts into the -// final object. This operation may take several minutes. -// -// See http://goo.gl/2Z7Tw for details. -func (m *Multi) Complete(parts []Part) error { - params := map[string][]string{ - "uploadId": {m.UploadId}, - } - c := completeUpload{} - for _, p := range parts { - c.Parts = append(c.Parts, completePart{p.N, p.ETag}) - } - sort.Sort(c.Parts) - data, err := xml.Marshal(&c) - if err != nil { - return err - } - for attempt := attempts.Start(); attempt.Next(); { - req := &request{ - method: "POST", - bucket: m.Bucket.Name, - path: m.Key, - params: params, - payload: bytes.NewReader(data), - } - err := m.Bucket.S3.query(req, nil) - if shouldRetry(err) && attempt.HasNext() { - continue - } - return err - } - panic("unreachable") -} - -// Abort deletes an unifinished multipart upload and any previously -// uploaded parts for it. -// -// After a multipart upload is aborted, no additional parts can be -// uploaded using it. However, if any part uploads are currently in -// progress, those part uploads might or might not succeed. As a result, -// it might be necessary to abort a given multipart upload multiple -// times in order to completely free all storage consumed by all parts. -// -// NOTE: If the described scenario happens to you, please report back to -// the goamz authors with details. In the future such retrying should be -// handled internally, but it's not clear what happens precisely (Is an -// error returned? Is the issue completely undetectable?). -// -// See http://goo.gl/dnyJw for details. -func (m *Multi) Abort() error { - params := map[string][]string{ - "uploadId": {m.UploadId}, - } - for attempt := attempts.Start(); attempt.Next(); { - req := &request{ - method: "DELETE", - bucket: m.Bucket.Name, - path: m.Key, - params: params, - } - err := m.Bucket.S3.query(req, nil) - if shouldRetry(err) && attempt.HasNext() { - continue - } - return err - } - panic("unreachable") -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi_test.go deleted file mode 100644 index ec64fef52..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/multi_test.go +++ /dev/null @@ -1,425 +0,0 @@ -package s3_test - -import ( - "encoding/xml" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "gopkg.in/check.v1" - "io" - "io/ioutil" - "strings" -) - -func (s *S) TestInitMulti(c *check.C) { - testServer.Response(200, nil, InitMultiResultDump) - b := s.s3.Bucket("sample") - - metadata := make(map[string][]string) - metadata["key1"] = []string{"value1"} - metadata["key2"] = []string{"value2"} - options := s3.Options{ - SSE: true, - Meta: metadata, - ContentEncoding: "text/utf8", - CacheControl: "no-cache", - RedirectLocation: "http://github.com/crowdmob/goamz", - ContentMD5: "0000000000000000", - } - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, options) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "POST") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Header["Content-Type"], check.DeepEquals, []string{"text/plain"}) - c.Assert(req.Header["X-Amz-Acl"], check.DeepEquals, []string{"private"}) - c.Assert(req.Form["uploads"], check.DeepEquals, []string{""}) - - c.Assert(req.Header["X-Amz-Server-Side-Encryption"], check.DeepEquals, []string{"AES256"}) - c.Assert(req.Header["Content-Encoding"], check.DeepEquals, []string{"text/utf8"}) - c.Assert(req.Header["Cache-Control"], check.DeepEquals, []string{"no-cache"}) - c.Assert(req.Header["Content-Md5"], check.DeepEquals, []string{"0000000000000000"}) - c.Assert(req.Header["X-Amz-Website-Redirect-Location"], check.DeepEquals, []string{"http://github.com/crowdmob/goamz"}) - c.Assert(req.Header["X-Amz-Meta-Key1"], check.DeepEquals, []string{"value1"}) - c.Assert(req.Header["X-Amz-Meta-Key2"], check.DeepEquals, []string{"value2"}) - - c.Assert(multi.UploadId, check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") -} - -func (s *S) TestMultiNoPreviousUpload(c *check.C) { - // Don't retry the NoSuchUpload error. - s.DisableRetries() - - testServer.Response(404, nil, NoSuchUploadErrorDump) - testServer.Response(200, nil, InitMultiResultDump) - - b := s.s3.Bucket("sample") - - multi, err := b.Multi("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/") - c.Assert(req.Form["uploads"], check.DeepEquals, []string{""}) - c.Assert(req.Form["prefix"], check.DeepEquals, []string{"multi"}) - - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "POST") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["uploads"], check.DeepEquals, []string{""}) - - c.Assert(multi.UploadId, check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") -} - -func (s *S) TestMultiReturnOld(c *check.C) { - testServer.Response(200, nil, ListMultiResultDump) - - b := s.s3.Bucket("sample") - - multi, err := b.Multi("multi1", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - c.Assert(multi.Key, check.Equals, "multi1") - c.Assert(multi.UploadId, check.Equals, "iUVug89pPvSswrikD") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/") - c.Assert(req.Form["uploads"], check.DeepEquals, []string{""}) - c.Assert(req.Form["prefix"], check.DeepEquals, []string{"multi1"}) -} - -func (s *S) TestListParts(c *check.C) { - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(200, nil, ListPartsResultDump1) - testServer.Response(404, nil, NoSuchUploadErrorDump) // :-( - testServer.Response(200, nil, ListPartsResultDump2) - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - parts, err := multi.ListParts() - c.Assert(err, check.IsNil) - c.Assert(parts, check.HasLen, 3) - c.Assert(parts[0].N, check.Equals, 1) - c.Assert(parts[0].Size, check.Equals, int64(5)) - c.Assert(parts[0].ETag, check.Equals, `"ffc88b4ca90a355f8ddba6b2c3b2af5c"`) - c.Assert(parts[1].N, check.Equals, 2) - c.Assert(parts[1].Size, check.Equals, int64(5)) - c.Assert(parts[1].ETag, check.Equals, `"d067a0fa9dc61a6e7195ca99696b5a89"`) - c.Assert(parts[2].N, check.Equals, 3) - c.Assert(parts[2].Size, check.Equals, int64(5)) - c.Assert(parts[2].ETag, check.Equals, `"49dcd91231f801159e893fb5c6674985"`) - testServer.WaitRequest() - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") - c.Assert(req.Form["max-parts"], check.DeepEquals, []string{"1000"}) - - testServer.WaitRequest() // The internal error. - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") - c.Assert(req.Form["max-parts"], check.DeepEquals, []string{"1000"}) - c.Assert(req.Form["part-number-marker"], check.DeepEquals, []string{"2"}) -} - -func (s *S) TestPutPart(c *check.C) { - headers := map[string]string{ - "ETag": `"26f90efd10d614f100252ff56d88dad8"`, - } - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(200, headers, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - part, err := multi.PutPart(1, strings.NewReader("")) - c.Assert(err, check.IsNil) - c.Assert(part.N, check.Equals, 1) - c.Assert(part.Size, check.Equals, int64(8)) - c.Assert(part.ETag, check.Equals, headers["ETag"]) - - testServer.WaitRequest() - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"1"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"8"}) - c.Assert(req.Header["Content-Md5"], check.DeepEquals, []string{"JvkO/RDWFPEAJS/1bYja2A=="}) -} - -func (s *S) TestPutPartCopy(c *check.C) { - testServer.Response(200, nil, InitMultiResultDump) - // PutPartCopy makes a Head request internally to verify access to the source object - // and obtain its size - testServer.Response(200, nil, "content") - testServer.Response(200, nil, PutCopyResultDump) - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - res, part, err := multi.PutPartCopy(1, s3.CopyOptions{}, "source-bucket/\u00FCber-fil\u00E9.jpg") - c.Assert(err, check.IsNil) - c.Assert(part.N, check.Equals, 1) - c.Assert(part.Size, check.Equals, int64(7)) - c.Assert(res, check.DeepEquals, &s3.CopyObjectResult{ - ETag: `"9b2cf535f27731c974343645a3985328"`, - LastModified: `2009-10-28T22:32:00`}) - - // Verify the Head request - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "POST") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - c.Assert(err, check.IsNil) - - testServer.WaitRequest() - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"1"}) - c.Assert(req.Header["X-Amz-Copy-Source"], check.DeepEquals, []string{`source-bucket%2F%C3%BCber-fil%C3%A9.jpg`}) -} - -func readAll(r io.Reader) string { - data, err := ioutil.ReadAll(r) - if err != nil { - panic(err) - } - return string(data) -} - -func (s *S) TestPutAllNoPreviousUpload(c *check.C) { - // Don't retry the NoSuchUpload error. - s.DisableRetries() - - etag1 := map[string]string{"ETag": `"etag1"`} - etag2 := map[string]string{"ETag": `"etag2"`} - etag3 := map[string]string{"ETag": `"etag3"`} - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(404, nil, NoSuchUploadErrorDump) - testServer.Response(200, etag1, "") - testServer.Response(200, etag2, "") - testServer.Response(200, etag3, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - parts, err := multi.PutAll(strings.NewReader("part1part2last"), 5) - c.Assert(parts, check.HasLen, 3) - c.Assert(parts[0].ETag, check.Equals, `"etag1"`) - c.Assert(parts[1].ETag, check.Equals, `"etag2"`) - c.Assert(parts[2].ETag, check.Equals, `"etag3"`) - c.Assert(err, check.IsNil) - - // Init - testServer.WaitRequest() - - // List old parts. Won't find anything. - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - - // Send part 1. - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"1"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"5"}) - c.Assert(readAll(req.Body), check.Equals, "part1") - - // Send part 2. - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"2"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"5"}) - c.Assert(readAll(req.Body), check.Equals, "part2") - - // Send part 3 with shorter body. - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"3"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"4"}) - c.Assert(readAll(req.Body), check.Equals, "last") -} - -func (s *S) TestPutAllZeroSizeFile(c *check.C) { - // Don't retry the NoSuchUpload error. - s.DisableRetries() - - etag1 := map[string]string{"ETag": `"etag1"`} - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(404, nil, NoSuchUploadErrorDump) - testServer.Response(200, etag1, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - // Must send at least one part, so that completing it will work. - parts, err := multi.PutAll(strings.NewReader(""), 5) - c.Assert(parts, check.HasLen, 1) - c.Assert(parts[0].ETag, check.Equals, `"etag1"`) - c.Assert(err, check.IsNil) - - // Init - testServer.WaitRequest() - - // List old parts. Won't find anything. - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - - // Send empty part. - req = testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"1"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"0"}) - c.Assert(readAll(req.Body), check.Equals, "") -} - -func (s *S) TestPutAllResume(c *check.C) { - etag2 := map[string]string{"ETag": `"etag2"`} - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(200, nil, ListPartsResultDump1) - testServer.Response(200, nil, ListPartsResultDump2) - testServer.Response(200, etag2, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - // "part1" and "part3" match the checksums in ResultDump1. - // The middle one is a mismatch (it refers to "part2"). - parts, err := multi.PutAll(strings.NewReader("part1partXpart3"), 5) - c.Assert(parts, check.HasLen, 3) - c.Assert(parts[0].N, check.Equals, 1) - c.Assert(parts[0].Size, check.Equals, int64(5)) - c.Assert(parts[0].ETag, check.Equals, `"ffc88b4ca90a355f8ddba6b2c3b2af5c"`) - c.Assert(parts[1].N, check.Equals, 2) - c.Assert(parts[1].Size, check.Equals, int64(5)) - c.Assert(parts[1].ETag, check.Equals, `"etag2"`) - c.Assert(parts[2].N, check.Equals, 3) - c.Assert(parts[2].Size, check.Equals, int64(5)) - c.Assert(parts[2].ETag, check.Equals, `"49dcd91231f801159e893fb5c6674985"`) - c.Assert(err, check.IsNil) - - // Init - testServer.WaitRequest() - - // List old parts, broken in two requests. - for i := 0; i < 2; i++ { - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - } - - // Send part 2, as it didn't match the checksum. - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form["partNumber"], check.DeepEquals, []string{"2"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"5"}) - c.Assert(readAll(req.Body), check.Equals, "partX") -} - -func (s *S) TestMultiComplete(c *check.C) { - testServer.Response(200, nil, InitMultiResultDump) - // Note the 200 response. Completing will hold the connection on some - // kind of long poll, and may return a late error even after a 200. - testServer.Response(200, nil, InternalErrorDump) - testServer.Response(200, nil, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - err = multi.Complete([]s3.Part{{2, `"ETag2"`, 32}, {1, `"ETag1"`, 64}}) - c.Assert(err, check.IsNil) - - testServer.WaitRequest() - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "POST") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") - - var payload struct { - XMLName xml.Name - Part []struct { - PartNumber int - ETag string - } - } - - dec := xml.NewDecoder(req.Body) - err = dec.Decode(&payload) - c.Assert(err, check.IsNil) - - c.Assert(payload.XMLName.Local, check.Equals, "CompleteMultipartUpload") - c.Assert(len(payload.Part), check.Equals, 2) - c.Assert(payload.Part[0].PartNumber, check.Equals, 1) - c.Assert(payload.Part[0].ETag, check.Equals, `"ETag1"`) - c.Assert(payload.Part[1].PartNumber, check.Equals, 2) - c.Assert(payload.Part[1].ETag, check.Equals, `"ETag2"`) -} - -func (s *S) TestMultiAbort(c *check.C) { - testServer.Response(200, nil, InitMultiResultDump) - testServer.Response(200, nil, "") - - b := s.s3.Bucket("sample") - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - err = multi.Abort() - c.Assert(err, check.IsNil) - - testServer.WaitRequest() - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "DELETE") - c.Assert(req.URL.Path, check.Equals, "/sample/multi") - c.Assert(req.Form.Get("uploadId"), check.Matches, "JNbR_[A-Za-z0-9.]+QQ--") -} - -func (s *S) TestListMulti(c *check.C) { - testServer.Response(200, nil, ListMultiResultDump) - - b := s.s3.Bucket("sample") - - multis, prefixes, err := b.ListMulti("", "/") - c.Assert(err, check.IsNil) - c.Assert(prefixes, check.DeepEquals, []string{"a/", "b/"}) - c.Assert(multis, check.HasLen, 2) - c.Assert(multis[0].Key, check.Equals, "multi1") - c.Assert(multis[0].UploadId, check.Equals, "iUVug89pPvSswrikD") - c.Assert(multis[1].Key, check.Equals, "multi2") - c.Assert(multis[1].UploadId, check.Equals, "DkirwsSvPp98guVUi") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/sample/") - c.Assert(req.Form["uploads"], check.DeepEquals, []string{""}) - c.Assert(req.Form["prefix"], check.DeepEquals, []string{""}) - c.Assert(req.Form["delimiter"], check.DeepEquals, []string{"/"}) - c.Assert(req.Form["max-uploads"], check.DeepEquals, []string{"1000"}) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/responses_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/responses_test.go deleted file mode 100644 index 22478b9c2..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/responses_test.go +++ /dev/null @@ -1,239 +0,0 @@ -package s3_test - -var PutCopyResultDump = ` - - - 2009-10-28T22:32:00 - "9b2cf535f27731c974343645a3985328" - -` - -var GetObjectErrorDump = ` - -NoSuchBucketThe specified bucket does not exist -non-existent-bucket3F1B667FAD71C3D8 -L4ee/zrm1irFXY5F45fKXIRdOf9ktsKY/8TDVawuMK2jWRb1RF84i1uBzkdNqS5D -` - -var GetListResultDump1 = ` - - - quotes - N - false - - Nelson - 2006-01-01T12:00:00.000Z - "828ef3fdfa96f00ad9f27c383fc9ac7f" - 5 - STANDARD - - bcaf161ca5fb16fd081034f - webfile - - - - Neo - 2006-01-01T12:00:00.000Z - "828ef3fdfa96f00ad9f27c383fc9ac7f" - 4 - STANDARD - - bcaf1ffd86a5fb16fd081034f - webfile - - - -` - -var GetListResultDump2 = ` - - example-bucket - photos/2006/ - some-marker - 1000 - / - false - - - photos/2006/feb/ - - - photos/2006/jan/ - - -` - -var InitMultiResultDump = ` - - - sample - multi - JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ-- - -` - -var ListPartsResultDump1 = ` - - - sample - multi - JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ-- - - bb5c0f63b0b25f2d099c - joe - - - bb5c0f63b0b25f2d099c - joe - - STANDARD - 0 - 2 - 2 - true - - 1 - 2013-01-30T13:45:51.000Z - "ffc88b4ca90a355f8ddba6b2c3b2af5c" - 5 - - - 2 - 2013-01-30T13:45:52.000Z - "d067a0fa9dc61a6e7195ca99696b5a89" - 5 - - -` - -var ListPartsResultDump2 = ` - - - sample - multi - JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ-- - - bb5c0f63b0b25f2d099c - joe - - - bb5c0f63b0b25f2d099c - joe - - STANDARD - 2 - 3 - 2 - false - - 3 - 2013-01-30T13:46:50.000Z - "49dcd91231f801159e893fb5c6674985" - 5 - - -` - -var ListMultiResultDump = ` - - - goamz-test-bucket-us-east-1-akiajk3wyewhctyqbf7a - - - multi1 - iUVug89pPvSswrikD72p8uO62EzhNtpDxRmwC5WSiWDdK9SfzmDqe3xpP1kMWimyimSnz4uzFc3waVM5ufrKYQ-- - / - 1000 - false - - multi1 - iUVug89pPvSswrikD - - bb5c0f63b0b25f2d0 - gustavoniemeyer - - - bb5c0f63b0b25f2d0 - gustavoniemeyer - - STANDARD - 2013-01-30T18:15:47.000Z - - - multi2 - DkirwsSvPp98guVUi - - bb5c0f63b0b25f2d0 - joe - - - bb5c0f63b0b25f2d0 - joe - - STANDARD - 2013-01-30T18:15:47.000Z - - - a/ - - - b/ - - -` - -var NoSuchUploadErrorDump = ` - - - NoSuchUpload - Not relevant - sample - 3F1B667FAD71C3D8 - kjhwqk - -` - -var InternalErrorDump = ` - - - InternalError - Not relevant - sample - 3F1B667FAD71C3D8 - kjhwqk - -` - -var GetServiceDump = ` - - - - bcaf1ffd86f461ca5fb16fd081034f - webfile - - - - quotes - 2006-02-03T16:45:09.000Z - - - samples - 2006-02-03T16:41:58.000Z - - - -` - -var GetLocationUsStandard = ` - - -` - -var GetLocationUsWest1 = ` - -us-west-1 -` - -var BucketWebsiteConfigurationDump = ` -example.com` diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3.go deleted file mode 100644 index c48003303..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3.go +++ /dev/null @@ -1,1248 +0,0 @@ -// -// goamz - Go packages to interact with the Amazon Web Services. -// -// https://wiki.ubuntu.com/goamz -// -// Copyright (c) 2011 Canonical Ltd. -// -// Written by Gustavo Niemeyer -// - -package s3 - -import ( - "bytes" - "crypto/hmac" - "crypto/md5" - "crypto/sha1" - "encoding/base64" - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "net/http/httputil" - "net/url" - "strconv" - "strings" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" -) - -const debug = false - -// The S3 type encapsulates operations with an S3 region. -type S3 struct { - aws.Auth - aws.Region - ConnectTimeout time.Duration - ReadTimeout time.Duration - Signature int - private byte // Reserve the right of using private data. -} - -// The Bucket type encapsulates operations with an S3 bucket. -type Bucket struct { - *S3 - Name string -} - -// The Owner type represents the owner of the object in an S3 bucket. -type Owner struct { - ID string - DisplayName string -} - -// Fold options into an Options struct -// -type Options struct { - SSE bool - SSECustomerAlgorithm string - SSECustomerKey string - SSECustomerKeyMD5 string - Meta map[string][]string - ContentEncoding string - CacheControl string - RedirectLocation string - ContentMD5 string - ContentDisposition string - Range string - // What else? - //// The following become headers so they are []strings rather than strings... I think - // x-amz-storage-class []string -} - -type CopyOptions struct { - Options - CopySourceOptions string - MetadataDirective string - ContentType string -} - -// CopyObjectResult is the output from a Copy request -type CopyObjectResult struct { - ETag string - LastModified string -} - -var attempts = aws.AttemptStrategy{ - Min: 5, - Total: 5 * time.Second, - Delay: 200 * time.Millisecond, -} - -// New creates a new S3. -func New(auth aws.Auth, region aws.Region) *S3 { - return &S3{auth, region, 0, 0, 0, aws.V2Signature} -} - -// Bucket returns a Bucket with the given name. -func (s3 *S3) Bucket(name string) *Bucket { - if s3.Region.S3BucketEndpoint != "" || s3.Region.S3LowercaseBucket { - name = strings.ToLower(name) - } - return &Bucket{s3, name} -} - -type BucketInfo struct { - Name string - CreationDate string -} - -type GetServiceResp struct { - Owner Owner - Buckets []BucketInfo `xml:">Bucket"` -} - -// GetService gets a list of all buckets owned by an account. -// -// See http://goo.gl/wbHkGj for details. -func (s3 *S3) GetService() (*GetServiceResp, error) { - bucket := s3.Bucket("") - - r, err := bucket.Get("") - if err != nil { - return nil, err - } - - // Parse the XML response. - var resp GetServiceResp - if err = xml.Unmarshal(r, &resp); err != nil { - return nil, err - } - - return &resp, nil -} - -var createBucketConfiguration = ` - %s -` - -// locationConstraint returns an io.Reader specifying a LocationConstraint if -// required for the region. -// -// See http://goo.gl/bh9Kq for details. -func (s3 *S3) locationConstraint() io.Reader { - constraint := "" - if s3.Region.S3LocationConstraint { - constraint = fmt.Sprintf(createBucketConfiguration, s3.Region.Name) - } - return strings.NewReader(constraint) -} - -type ACL string - -const ( - Private = ACL("private") - PublicRead = ACL("public-read") - PublicReadWrite = ACL("public-read-write") - AuthenticatedRead = ACL("authenticated-read") - BucketOwnerRead = ACL("bucket-owner-read") - BucketOwnerFull = ACL("bucket-owner-full-control") -) - -// PutBucket creates a new bucket. -// -// See http://goo.gl/ndjnR for details. -func (b *Bucket) PutBucket(perm ACL) error { - headers := map[string][]string{ - "x-amz-acl": {string(perm)}, - } - req := &request{ - method: "PUT", - bucket: b.Name, - path: "/", - headers: headers, - payload: b.locationConstraint(), - } - return b.S3.query(req, nil) -} - -// DelBucket removes an existing S3 bucket. All objects in the bucket must -// be removed before the bucket itself can be removed. -// -// See http://goo.gl/GoBrY for details. -func (b *Bucket) DelBucket() (err error) { - req := &request{ - method: "DELETE", - bucket: b.Name, - path: "/", - } - for attempt := attempts.Start(); attempt.Next(); { - err = b.S3.query(req, nil) - if !shouldRetry(err) { - break - } - } - return err -} - -// Get retrieves an object from an S3 bucket. -// -// See http://goo.gl/isCO7 for details. -func (b *Bucket) Get(path string) (data []byte, err error) { - body, err := b.GetReader(path) - if err != nil { - return nil, err - } - data, err = ioutil.ReadAll(body) - body.Close() - return data, err -} - -// GetReader retrieves an object from an S3 bucket, -// returning the body of the HTTP response. -// It is the caller's responsibility to call Close on rc when -// finished reading. -func (b *Bucket) GetReader(path string) (rc io.ReadCloser, err error) { - resp, err := b.GetResponse(path) - if resp != nil { - return resp.Body, err - } - return nil, err -} - -// GetResponse retrieves an object from an S3 bucket, -// returning the HTTP response. -// It is the caller's responsibility to call Close on rc when -// finished reading -func (b *Bucket) GetResponse(path string) (resp *http.Response, err error) { - return b.GetResponseWithHeaders(path, make(http.Header)) -} - -// GetReaderWithHeaders retrieves an object from an S3 bucket -// Accepts custom headers to be sent as the second parameter -// returning the body of the HTTP response. -// It is the caller's responsibility to call Close on rc when -// finished reading -func (b *Bucket) GetResponseWithHeaders(path string, headers map[string][]string) (resp *http.Response, err error) { - req := &request{ - bucket: b.Name, - path: path, - headers: headers, - } - err = b.S3.prepare(req) - if err != nil { - return nil, err - } - for attempt := attempts.Start(); attempt.Next(); { - resp, err := b.S3.run(req, nil) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return nil, err - } - return resp, nil - } - panic("unreachable") -} - -// Exists checks whether or not an object exists on an S3 bucket using a HEAD request. -func (b *Bucket) Exists(path string) (exists bool, err error) { - req := &request{ - method: "HEAD", - bucket: b.Name, - path: path, - } - err = b.S3.prepare(req) - if err != nil { - return - } - for attempt := attempts.Start(); attempt.Next(); { - resp, err := b.S3.run(req, nil) - - if shouldRetry(err) && attempt.HasNext() { - continue - } - - if err != nil { - // We can treat a 403 or 404 as non existance - if e, ok := err.(*Error); ok && (e.StatusCode == 403 || e.StatusCode == 404) { - return false, nil - } - return false, err - } - - if resp.StatusCode/100 == 2 { - exists = true - } - if resp.Body != nil { - resp.Body.Close() - } - return exists, err - } - return false, fmt.Errorf("S3 Currently Unreachable") -} - -// Head HEADs an object in the S3 bucket, returns the response with -// no body see http://bit.ly/17K1ylI -func (b *Bucket) Head(path string, headers map[string][]string) (*http.Response, error) { - req := &request{ - method: "HEAD", - bucket: b.Name, - path: path, - headers: headers, - } - err := b.S3.prepare(req) - if err != nil { - return nil, err - } - - for attempt := attempts.Start(); attempt.Next(); { - resp, err := b.S3.run(req, nil) - if shouldRetry(err) && attempt.HasNext() { - continue - } - if err != nil { - return nil, err - } - return resp, err - } - return nil, fmt.Errorf("S3 Currently Unreachable") -} - -// Put inserts an object into the S3 bucket. -// -// See http://goo.gl/FEBPD for details. -func (b *Bucket) Put(path string, data []byte, contType string, perm ACL, options Options) error { - body := bytes.NewBuffer(data) - return b.PutReader(path, body, int64(len(data)), contType, perm, options) -} - -// PutCopy puts a copy of an object given by the key path into bucket b using b.Path as the target key -func (b *Bucket) PutCopy(path string, perm ACL, options CopyOptions, source string) (*CopyObjectResult, error) { - headers := map[string][]string{ - "x-amz-acl": {string(perm)}, - "x-amz-copy-source": {url.QueryEscape(source)}, - } - options.addHeaders(headers) - req := &request{ - method: "PUT", - bucket: b.Name, - path: path, - headers: headers, - } - resp := &CopyObjectResult{} - err := b.S3.query(req, resp) - if err != nil { - return resp, err - } - return resp, nil -} - -// PutReader inserts an object into the S3 bucket by consuming data -// from r until EOF. -func (b *Bucket) PutReader(path string, r io.Reader, length int64, contType string, perm ACL, options Options) error { - headers := map[string][]string{ - "Content-Length": {strconv.FormatInt(length, 10)}, - "Content-Type": {contType}, - "x-amz-acl": {string(perm)}, - } - options.addHeaders(headers) - req := &request{ - method: "PUT", - bucket: b.Name, - path: path, - headers: headers, - payload: r, - } - return b.S3.query(req, nil) -} - -// addHeaders adds o's specified fields to headers -func (o Options) addHeaders(headers map[string][]string) { - if o.SSE { - headers["x-amz-server-side-encryption"] = []string{"AES256"} - } else if len(o.SSECustomerAlgorithm) != 0 && len(o.SSECustomerKey) != 0 && len(o.SSECustomerKeyMD5) != 0 { - // Amazon-managed keys and customer-managed keys are mutually exclusive - headers["x-amz-server-side-encryption-customer-algorithm"] = []string{o.SSECustomerAlgorithm} - headers["x-amz-server-side-encryption-customer-key"] = []string{o.SSECustomerKey} - headers["x-amz-server-side-encryption-customer-key-MD5"] = []string{o.SSECustomerKeyMD5} - } - if len(o.Range) != 0 { - headers["Range"] = []string{o.Range} - } - if len(o.ContentEncoding) != 0 { - headers["Content-Encoding"] = []string{o.ContentEncoding} - } - if len(o.CacheControl) != 0 { - headers["Cache-Control"] = []string{o.CacheControl} - } - if len(o.ContentMD5) != 0 { - headers["Content-MD5"] = []string{o.ContentMD5} - } - if len(o.RedirectLocation) != 0 { - headers["x-amz-website-redirect-location"] = []string{o.RedirectLocation} - } - if len(o.ContentDisposition) != 0 { - headers["Content-Disposition"] = []string{o.ContentDisposition} - } - for k, v := range o.Meta { - headers["x-amz-meta-"+k] = v - } -} - -// addHeaders adds o's specified fields to headers -func (o CopyOptions) addHeaders(headers map[string][]string) { - o.Options.addHeaders(headers) - if len(o.MetadataDirective) != 0 { - headers["x-amz-metadata-directive"] = []string{o.MetadataDirective} - } - if len(o.CopySourceOptions) != 0 { - headers["x-amz-copy-source-range"] = []string{o.CopySourceOptions} - } - if len(o.ContentType) != 0 { - headers["Content-Type"] = []string{o.ContentType} - } -} - -func makeXmlBuffer(doc []byte) *bytes.Buffer { - buf := new(bytes.Buffer) - buf.WriteString(xml.Header) - buf.Write(doc) - return buf -} - -type IndexDocument struct { - Suffix string `xml:"Suffix"` -} - -type ErrorDocument struct { - Key string `xml:"Key"` -} - -type RoutingRule struct { - ConditionKeyPrefixEquals string `xml:"Condition>KeyPrefixEquals"` - RedirectReplaceKeyPrefixWith string `xml:"Redirect>ReplaceKeyPrefixWith,omitempty"` - RedirectReplaceKeyWith string `xml:"Redirect>ReplaceKeyWith,omitempty"` -} - -type RedirectAllRequestsTo struct { - HostName string `xml:"HostName"` - Protocol string `xml:"Protocol,omitempty"` -} - -type WebsiteConfiguration struct { - XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ WebsiteConfiguration"` - IndexDocument *IndexDocument `xml:"IndexDocument,omitempty"` - ErrorDocument *ErrorDocument `xml:"ErrorDocument,omitempty"` - RoutingRules *[]RoutingRule `xml:"RoutingRules>RoutingRule,omitempty"` - RedirectAllRequestsTo *RedirectAllRequestsTo `xml:"RedirectAllRequestsTo,omitempty"` -} - -// PutBucketWebsite configures a bucket as a website. -// -// See http://goo.gl/TpRlUy for details. -func (b *Bucket) PutBucketWebsite(configuration WebsiteConfiguration) error { - doc, err := xml.Marshal(configuration) - if err != nil { - return err - } - - buf := makeXmlBuffer(doc) - - return b.PutBucketSubresource("website", buf, int64(buf.Len())) -} - -func (b *Bucket) PutBucketSubresource(subresource string, r io.Reader, length int64) error { - headers := map[string][]string{ - "Content-Length": {strconv.FormatInt(length, 10)}, - } - req := &request{ - path: "/", - method: "PUT", - bucket: b.Name, - headers: headers, - payload: r, - params: url.Values{subresource: {""}}, - } - - return b.S3.query(req, nil) -} - -// Del removes an object from the S3 bucket. -// -// See http://goo.gl/APeTt for details. -func (b *Bucket) Del(path string) error { - req := &request{ - method: "DELETE", - bucket: b.Name, - path: path, - } - return b.S3.query(req, nil) -} - -type Delete struct { - Quiet bool `xml:"Quiet,omitempty"` - Objects []Object `xml:"Object"` -} - -type Object struct { - Key string `xml:"Key"` - VersionId string `xml:"VersionId,omitempty"` -} - -// DelMulti removes up to 1000 objects from the S3 bucket. -// -// See http://goo.gl/jx6cWK for details. -func (b *Bucket) DelMulti(objects Delete) error { - doc, err := xml.Marshal(objects) - if err != nil { - return err - } - - buf := makeXmlBuffer(doc) - digest := md5.New() - size, err := digest.Write(buf.Bytes()) - if err != nil { - return err - } - - headers := map[string][]string{ - "Content-Length": {strconv.FormatInt(int64(size), 10)}, - "Content-MD5": {base64.StdEncoding.EncodeToString(digest.Sum(nil))}, - "Content-Type": {"text/xml"}, - } - req := &request{ - path: "/", - method: "POST", - params: url.Values{"delete": {""}}, - bucket: b.Name, - headers: headers, - payload: buf, - } - - return b.S3.query(req, nil) -} - -// The ListResp type holds the results of a List bucket operation. -type ListResp struct { - Name string - Prefix string - Delimiter string - Marker string - MaxKeys int - // IsTruncated is true if the results have been truncated because - // there are more keys and prefixes than can fit in MaxKeys. - // N.B. this is the opposite sense to that documented (incorrectly) in - // http://goo.gl/YjQTc - IsTruncated bool - Contents []Key - CommonPrefixes []string `xml:">Prefix"` - // if IsTruncated is true, pass NextMarker as marker argument to List() - // to get the next set of keys - NextMarker string -} - -// The Key type represents an item stored in an S3 bucket. -type Key struct { - Key string - LastModified string - Size int64 - // ETag gives the hex-encoded MD5 sum of the contents, - // surrounded with double-quotes. - ETag string - StorageClass string - Owner Owner -} - -// List returns information about objects in an S3 bucket. -// -// The prefix parameter limits the response to keys that begin with the -// specified prefix. -// -// The delim parameter causes the response to group all of the keys that -// share a common prefix up to the next delimiter in a single entry within -// the CommonPrefixes field. You can use delimiters to separate a bucket -// into different groupings of keys, similar to how folders would work. -// -// The marker parameter specifies the key to start with when listing objects -// in a bucket. Amazon S3 lists objects in alphabetical order and -// will return keys alphabetically greater than the marker. -// -// The max parameter specifies how many keys + common prefixes to return in -// the response. The default is 1000. -// -// For example, given these keys in a bucket: -// -// index.html -// index2.html -// photos/2006/January/sample.jpg -// photos/2006/February/sample2.jpg -// photos/2006/February/sample3.jpg -// photos/2006/February/sample4.jpg -// -// Listing this bucket with delimiter set to "/" would yield the -// following result: -// -// &ListResp{ -// Name: "sample-bucket", -// MaxKeys: 1000, -// Delimiter: "/", -// Contents: []Key{ -// {Key: "index.html", "index2.html"}, -// }, -// CommonPrefixes: []string{ -// "photos/", -// }, -// } -// -// Listing the same bucket with delimiter set to "/" and prefix set to -// "photos/2006/" would yield the following result: -// -// &ListResp{ -// Name: "sample-bucket", -// MaxKeys: 1000, -// Delimiter: "/", -// Prefix: "photos/2006/", -// CommonPrefixes: []string{ -// "photos/2006/February/", -// "photos/2006/January/", -// }, -// } -// -// See http://goo.gl/YjQTc for details. -func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, err error) { - params := map[string][]string{ - "prefix": {prefix}, - "delimiter": {delim}, - "marker": {marker}, - } - if max != 0 { - params["max-keys"] = []string{strconv.FormatInt(int64(max), 10)} - } - req := &request{ - bucket: b.Name, - params: params, - } - result = &ListResp{} - for attempt := attempts.Start(); attempt.Next(); { - err = b.S3.query(req, result) - if !shouldRetry(err) { - break - } - } - if err != nil { - return nil, err - } - // if NextMarker is not returned, it should be set to the name of last key, - // so let's do it so that each caller doesn't have to - if result.IsTruncated && result.NextMarker == "" { - n := len(result.Contents) - if n > 0 { - result.NextMarker = result.Contents[n-1].Key - } - } - return result, nil -} - -// The VersionsResp type holds the results of a list bucket Versions operation. -type VersionsResp struct { - Name string - Prefix string - KeyMarker string - VersionIdMarker string - MaxKeys int - Delimiter string - IsTruncated bool - Versions []Version `xml:"Version"` - CommonPrefixes []string `xml:">Prefix"` -} - -// The Version type represents an object version stored in an S3 bucket. -type Version struct { - Key string - VersionId string - IsLatest bool - LastModified string - // ETag gives the hex-encoded MD5 sum of the contents, - // surrounded with double-quotes. - ETag string - Size int64 - Owner Owner - StorageClass string -} - -func (b *Bucket) Versions(prefix, delim, keyMarker string, versionIdMarker string, max int) (result *VersionsResp, err error) { - params := map[string][]string{ - "versions": {""}, - "prefix": {prefix}, - "delimiter": {delim}, - } - - if len(versionIdMarker) != 0 { - params["version-id-marker"] = []string{versionIdMarker} - } - if len(keyMarker) != 0 { - params["key-marker"] = []string{keyMarker} - } - - if max != 0 { - params["max-keys"] = []string{strconv.FormatInt(int64(max), 10)} - } - req := &request{ - bucket: b.Name, - params: params, - } - result = &VersionsResp{} - for attempt := attempts.Start(); attempt.Next(); { - err = b.S3.query(req, result) - if !shouldRetry(err) { - break - } - } - if err != nil { - return nil, err - } - return result, nil -} - -type GetLocationResp struct { - Location string `xml:",innerxml"` -} - -func (b *Bucket) Location() (string, error) { - r, err := b.Get("/?location") - if err != nil { - return "", err - } - - // Parse the XML response. - var resp GetLocationResp - if err = xml.Unmarshal(r, &resp); err != nil { - return "", err - } - - if resp.Location == "" { - return "us-east-1", nil - } else { - return resp.Location, nil - } -} - -// URL returns a non-signed URL that allows retriving the -// object at path. It only works if the object is publicly -// readable (see SignedURL). -func (b *Bucket) URL(path string) string { - req := &request{ - bucket: b.Name, - path: path, - } - err := b.S3.prepare(req) - if err != nil { - panic(err) - } - u, err := req.url() - if err != nil { - panic(err) - } - u.RawQuery = "" - return u.String() -} - -// SignedURL returns a signed URL that allows anyone holding the URL -// to retrieve the object at path. The signature is valid until expires. -func (b *Bucket) SignedURL(path string, expires time.Time) string { - return b.SignedURLWithArgs(path, expires, nil, nil) -} - -// SignedURLWithArgs returns a signed URL that allows anyone holding the URL -// to retrieve the object at path. The signature is valid until expires. -func (b *Bucket) SignedURLWithArgs(path string, expires time.Time, params url.Values, headers http.Header) string { - return b.SignedURLWithMethod("GET", path, expires, params, headers) -} - -// SignedURLWithMethod returns a signed URL that allows anyone holding the URL -// to either retrieve the object at path or make a HEAD request against it. The signature is valid until expires. -func (b *Bucket) SignedURLWithMethod(method, path string, expires time.Time, params url.Values, headers http.Header) string { - var uv = url.Values{} - - if params != nil { - uv = params - } - - if b.S3.Signature == aws.V2Signature { - uv.Set("Expires", strconv.FormatInt(expires.Unix(), 10)) - } else { - uv.Set("X-Amz-Expires", strconv.FormatInt(expires.Unix()-time.Now().Unix(), 10)) - } - - req := &request{ - method: method, - bucket: b.Name, - path: path, - params: uv, - headers: headers, - } - err := b.S3.prepare(req) - if err != nil { - panic(err) - } - u, err := req.url() - if err != nil { - panic(err) - } - if b.S3.Auth.Token() != "" { - return u.String() + "&x-amz-security-token=" + url.QueryEscape(req.headers["X-Amz-Security-Token"][0]) - } else { - return u.String() - } -} - -// UploadSignedURL returns a signed URL that allows anyone holding the URL -// to upload the object at path. The signature is valid until expires. -// contenttype is a string like image/png -// path is the resource name in s3 terminalogy like images/ali.png [obviously exclusing the bucket name itself] -func (b *Bucket) UploadSignedURL(path, method, content_type string, expires time.Time) string { - expire_date := expires.Unix() - if method != "POST" { - method = "PUT" - } - - a := b.S3.Auth - tokenData := "" - - if a.Token() != "" { - tokenData = "x-amz-security-token:" + a.Token() + "\n" - } - - stringToSign := method + "\n\n" + content_type + "\n" + strconv.FormatInt(expire_date, 10) + "\n" + tokenData + "/" + b.Name + "/" + path - secretKey := a.SecretKey - accessId := a.AccessKey - mac := hmac.New(sha1.New, []byte(secretKey)) - mac.Write([]byte(stringToSign)) - macsum := mac.Sum(nil) - signature := base64.StdEncoding.EncodeToString([]byte(macsum)) - signature = strings.TrimSpace(signature) - - signedurl, err := url.Parse("https://" + b.Name + ".s3.amazonaws.com/") - if err != nil { - log.Println("ERROR sining url for S3 upload", err) - return "" - } - signedurl.Path += path - params := url.Values{} - params.Add("AWSAccessKeyId", accessId) - params.Add("Expires", strconv.FormatInt(expire_date, 10)) - params.Add("Signature", signature) - if a.Token() != "" { - params.Add("x-amz-security-token", a.Token()) - } - - signedurl.RawQuery = params.Encode() - return signedurl.String() -} - -// PostFormArgs returns the action and input fields needed to allow anonymous -// uploads to a bucket within the expiration limit -// Additional conditions can be specified with conds -func (b *Bucket) PostFormArgsEx(path string, expires time.Time, redirect string, conds []string) (action string, fields map[string]string) { - conditions := make([]string, 0) - fields = map[string]string{ - "AWSAccessKeyId": b.Auth.AccessKey, - "key": path, - } - - if conds != nil { - conditions = append(conditions, conds...) - } - - conditions = append(conditions, fmt.Sprintf("{\"key\": \"%s\"}", path)) - conditions = append(conditions, fmt.Sprintf("{\"bucket\": \"%s\"}", b.Name)) - if redirect != "" { - conditions = append(conditions, fmt.Sprintf("{\"success_action_redirect\": \"%s\"}", redirect)) - fields["success_action_redirect"] = redirect - } - - vExpiration := expires.Format("2006-01-02T15:04:05Z") - vConditions := strings.Join(conditions, ",") - policy := fmt.Sprintf("{\"expiration\": \"%s\", \"conditions\": [%s]}", vExpiration, vConditions) - policy64 := base64.StdEncoding.EncodeToString([]byte(policy)) - fields["policy"] = policy64 - - signer := hmac.New(sha1.New, []byte(b.Auth.SecretKey)) - signer.Write([]byte(policy64)) - fields["signature"] = base64.StdEncoding.EncodeToString(signer.Sum(nil)) - - action = fmt.Sprintf("%s/%s/", b.S3.Region.S3Endpoint, b.Name) - return -} - -// PostFormArgs returns the action and input fields needed to allow anonymous -// uploads to a bucket within the expiration limit -func (b *Bucket) PostFormArgs(path string, expires time.Time, redirect string) (action string, fields map[string]string) { - return b.PostFormArgsEx(path, expires, redirect, nil) -} - -type request struct { - method string - bucket string - path string - params url.Values - headers http.Header - baseurl string - payload io.Reader - prepared bool -} - -func (req *request) url() (*url.URL, error) { - u, err := url.Parse(req.baseurl) - if err != nil { - return nil, fmt.Errorf("bad S3 endpoint URL %q: %v", req.baseurl, err) - } - u.RawQuery = req.params.Encode() - u.Path = req.path - return u, nil -} - -// query prepares and runs the req request. -// If resp is not nil, the XML data contained in the response -// body will be unmarshalled on it. -func (s3 *S3) query(req *request, resp interface{}) error { - err := s3.prepare(req) - if err != nil { - return err - } - r, err := s3.run(req, resp) - if r != nil && r.Body != nil { - r.Body.Close() - } - return err -} - -// queryV4Signprepares and runs the req request, signed with aws v4 signatures. -// If resp is not nil, the XML data contained in the response -// body will be unmarshalled on it. -func (s3 *S3) queryV4Sign(req *request, resp interface{}) error { - if req.headers == nil { - req.headers = map[string][]string{} - } - - err := s3.setBaseURL(req) - if err != nil { - return err - } - - hreq, err := s3.setupHttpRequest(req) - if err != nil { - return err - } - - // req.Host must be set for V4 signature calculation - hreq.Host = hreq.URL.Host - - signer := aws.NewV4Signer(s3.Auth, "s3", s3.Region) - signer.IncludeXAmzContentSha256 = true - signer.Sign(hreq) - - _, err = s3.doHttpRequest(hreq, resp) - return err -} - -// Sets baseurl on req from bucket name and the region endpoint -func (s3 *S3) setBaseURL(req *request) error { - if req.bucket == "" { - req.baseurl = s3.Region.S3Endpoint - } else { - req.baseurl = s3.Region.S3BucketEndpoint - if req.baseurl == "" { - // Use the path method to address the bucket. - req.baseurl = s3.Region.S3Endpoint - req.path = "/" + req.bucket + req.path - } else { - // Just in case, prevent injection. - if strings.IndexAny(req.bucket, "/:@") >= 0 { - return fmt.Errorf("bad S3 bucket: %q", req.bucket) - } - req.baseurl = strings.Replace(req.baseurl, "${bucket}", req.bucket, -1) - } - } - - return nil -} - -// partiallyEscapedPath partially escapes the S3 path allowing for all S3 REST API calls. -// -// Some commands including: -// GET Bucket acl http://goo.gl/aoXflF -// GET Bucket cors http://goo.gl/UlmBdx -// GET Bucket lifecycle http://goo.gl/8Fme7M -// GET Bucket policy http://goo.gl/ClXIo3 -// GET Bucket location http://goo.gl/5lh8RD -// GET Bucket Logging http://goo.gl/sZ5ckF -// GET Bucket notification http://goo.gl/qSSZKD -// GET Bucket tagging http://goo.gl/QRvxnM -// require the first character after the bucket name in the path to be a literal '?' and -// not the escaped hex representation '%3F'. -func partiallyEscapedPath(path string) string { - pathEscapedAndSplit := strings.Split((&url.URL{Path: path}).String(), "/") - if len(pathEscapedAndSplit) >= 3 { - if len(pathEscapedAndSplit[2]) >= 3 { - // Check for the one "?" that should not be escaped. - if pathEscapedAndSplit[2][0:3] == "%3F" { - pathEscapedAndSplit[2] = "?" + pathEscapedAndSplit[2][3:] - } - } - } - return strings.Replace(strings.Join(pathEscapedAndSplit, "/"), "+", "%2B", -1) -} - -// prepare sets up req to be delivered to S3. -func (s3 *S3) prepare(req *request) error { - // Copy so they can be mutated without affecting on retries. - params := make(url.Values) - headers := make(http.Header) - for k, v := range req.params { - params[k] = v - } - for k, v := range req.headers { - headers[k] = v - } - req.params = params - req.headers = headers - - if !req.prepared { - req.prepared = true - if req.method == "" { - req.method = "GET" - } - - if !strings.HasPrefix(req.path, "/") { - req.path = "/" + req.path - } - - err := s3.setBaseURL(req) - if err != nil { - return err - } - } - - if s3.Auth.Token() != "" { - req.headers["X-Amz-Security-Token"] = []string{s3.Auth.Token()} - } - - if s3.Signature == aws.V2Signature { - // Always sign again as it's not clear how far the - // server has handled a previous attempt. - u, err := url.Parse(req.baseurl) - if err != nil { - return err - } - - signpathPatiallyEscaped := partiallyEscapedPath(req.path) - req.headers["Host"] = []string{u.Host} - req.headers["Date"] = []string{time.Now().In(time.UTC).Format(time.RFC1123)} - - sign(s3.Auth, req.method, signpathPatiallyEscaped, req.params, req.headers) - } else { - hreq, err := s3.setupHttpRequest(req) - if err != nil { - return err - } - - hreq.Host = hreq.URL.Host - signer := aws.NewV4Signer(s3.Auth, "s3", s3.Region) - signer.IncludeXAmzContentSha256 = true - signer.Sign(hreq) - - req.payload = hreq.Body - if _, ok := headers["Content-Length"]; ok { - req.headers["Content-Length"] = headers["Content-Length"] - } - } - return nil -} - -// Prepares an *http.Request for doHttpRequest -func (s3 *S3) setupHttpRequest(req *request) (*http.Request, error) { - // Copy so that signing the http request will not mutate it - headers := make(http.Header) - for k, v := range req.headers { - headers[k] = v - } - req.headers = headers - - u, err := req.url() - if err != nil { - return nil, err - } - u.Opaque = fmt.Sprintf("//%s%s", u.Host, partiallyEscapedPath(u.Path)) - - hreq := http.Request{ - URL: u, - Method: req.method, - ProtoMajor: 1, - ProtoMinor: 1, - Close: true, - Header: req.headers, - Form: req.params, - } - - if v, ok := req.headers["Content-Length"]; ok { - hreq.ContentLength, _ = strconv.ParseInt(v[0], 10, 64) - delete(req.headers, "Content-Length") - } - if req.payload != nil { - hreq.Body = ioutil.NopCloser(req.payload) - } - - return &hreq, nil -} - -// doHttpRequest sends hreq and returns the http response from the server. -// If resp is not nil, the XML data contained in the response -// body will be unmarshalled on it. -func (s3 *S3) doHttpRequest(hreq *http.Request, resp interface{}) (*http.Response, error) { - c := http.Client{ - Transport: &http.Transport{ - Dial: func(netw, addr string) (c net.Conn, err error) { - deadline := time.Now().Add(s3.ReadTimeout) - if s3.ConnectTimeout > 0 { - c, err = net.DialTimeout(netw, addr, s3.ConnectTimeout) - } else { - c, err = net.Dial(netw, addr) - } - if err != nil { - return - } - if s3.ReadTimeout > 0 { - err = c.SetDeadline(deadline) - } - return - }, - Proxy: http.ProxyFromEnvironment, - }, - } - - hresp, err := c.Do(hreq) - if err != nil { - return nil, err - } - if debug { - dump, _ := httputil.DumpResponse(hresp, true) - log.Printf("} -> %s\n", dump) - } - if hresp.StatusCode != 200 && hresp.StatusCode != 204 && hresp.StatusCode != 206 { - return nil, buildError(hresp) - } - if resp != nil { - err = xml.NewDecoder(hresp.Body).Decode(resp) - hresp.Body.Close() - - if debug { - log.Printf("goamz.s3> decoded xml into %#v", resp) - } - - } - return hresp, err -} - -// run sends req and returns the http response from the server. -// If resp is not nil, the XML data contained in the response -// body will be unmarshalled on it. -func (s3 *S3) run(req *request, resp interface{}) (*http.Response, error) { - if debug { - log.Printf("Running S3 request: %#v", req) - } - - hreq, err := s3.setupHttpRequest(req) - if err != nil { - return nil, err - } - - return s3.doHttpRequest(hreq, resp) -} - -// Error represents an error in an operation with S3. -type Error struct { - StatusCode int // HTTP status code (200, 403, ...) - Code string // EC2 error code ("UnsupportedOperation", ...) - Message string // The human-oriented error message - BucketName string - RequestId string - HostId string -} - -func (e *Error) Error() string { - return e.Message -} - -func buildError(r *http.Response) error { - if debug { - log.Printf("got error (status code %v)", r.StatusCode) - data, err := ioutil.ReadAll(r.Body) - if err != nil { - log.Printf("\tread error: %v", err) - } else { - log.Printf("\tdata:\n%s\n\n", data) - } - r.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - } - - err := Error{} - // TODO return error if Unmarshal fails? - xml.NewDecoder(r.Body).Decode(&err) - r.Body.Close() - err.StatusCode = r.StatusCode - if err.Message == "" { - err.Message = r.Status - } - if debug { - log.Printf("err: %#v\n", err) - } - return &err -} - -func shouldRetry(err error) bool { - if err == nil { - return false - } - switch err { - case io.ErrUnexpectedEOF, io.EOF: - return true - } - switch e := err.(type) { - case *net.DNSError: - return true - case *net.OpError: - switch e.Op { - case "read", "write": - return true - } - case *Error: - switch e.Code { - case "InternalError", "NoSuchUpload", "NoSuchBucket": - return true - } - } - return false -} - -func hasCode(err error, code string) bool { - s3err, ok := err.(*Error) - return ok && s3err.Code == code -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3_test.go deleted file mode 100644 index 7ba2157cc..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3_test.go +++ /dev/null @@ -1,486 +0,0 @@ -package s3_test - -import ( - "bytes" - "io/ioutil" - "net/http" - "testing" - "time" - - "github.com/crowdmob/goamz/testutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "gopkg.in/check.v1" -) - -func Test(t *testing.T) { - check.TestingT(t) -} - -type S struct { - s3 *s3.S3 -} - -var _ = check.Suite(&S{}) - -var testServer = testutil.NewHTTPServer() - -func (s *S) SetUpSuite(c *check.C) { - testServer.Start() - auth := aws.Auth{AccessKey: "abc", SecretKey: "123"} - s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL}) -} - -func (s *S) TearDownSuite(c *check.C) { - s3.SetAttemptStrategy(nil) -} - -func (s *S) SetUpTest(c *check.C) { - attempts := aws.AttemptStrategy{ - Total: 300 * time.Millisecond, - Delay: 100 * time.Millisecond, - } - s3.SetAttemptStrategy(&attempts) -} - -func (s *S) TearDownTest(c *check.C) { - testServer.Flush() -} - -func (s *S) DisableRetries() { - s3.SetAttemptStrategy(&aws.AttemptStrategy{}) -} - -// PutBucket docs: http://goo.gl/kBTCu - -func (s *S) TestPutBucket(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") -} - -// PutBucketWebsite docs: http://goo.gl/TpRlUy - -func (s *S) TestPutBucketWebsite(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - config := s3.WebsiteConfiguration{ - RedirectAllRequestsTo: &s3.RedirectAllRequestsTo{HostName: "example.com"}, - } - err := b.PutBucketWebsite(config) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - body, err := ioutil.ReadAll(req.Body) - req.Body.Close() - c.Assert(err, check.IsNil) - c.Assert(string(body), check.Equals, BucketWebsiteConfigurationDump) - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - c.Assert(req.URL.RawQuery, check.Equals, "website=") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") -} - -// Head docs: http://bit.ly/17K1ylI - -func (s *S) TestHead(c *check.C) { - testServer.Response(200, nil, "content") - - b := s.s3.Bucket("bucket") - resp, err := b.Head("name", nil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "HEAD") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - - c.Assert(err, check.IsNil) - c.Assert(resp.ContentLength, check.FitsTypeOf, int64(0)) - c.Assert(resp, check.FitsTypeOf, &http.Response{}) -} - -// DeleteBucket docs: http://goo.gl/GoBrY - -func (s *S) TestDelBucket(c *check.C) { - testServer.Response(204, nil, "") - - b := s.s3.Bucket("bucket") - err := b.DelBucket() - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "DELETE") - c.Assert(req.URL.Path, check.Equals, "/bucket/") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") -} - -// GetObject docs: http://goo.gl/isCO7 - -func (s *S) TestGet(c *check.C) { - testServer.Response(200, nil, "content") - - b := s.s3.Bucket("bucket") - data, err := b.Get("name") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "content") -} - -func (s *S) TestGetWithPlus(c *check.C) { - testServer.Response(200, nil, "content") - - b := s.s3.Bucket("bucket") - _, err := b.Get("has+plus") - - req := testServer.WaitRequest() - c.Assert(err, check.IsNil) - c.Assert(req.RequestURI, check.Equals, "http://localhost:4444/bucket/has%2Bplus") -} - -func (s *S) TestURL(c *check.C) { - testServer.Response(200, nil, "content") - - b := s.s3.Bucket("bucket") - url := b.URL("name") - r, err := http.Get(url) - c.Assert(err, check.IsNil) - data, err := ioutil.ReadAll(r.Body) - r.Body.Close() - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "content") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") -} - -func (s *S) TestGetReader(c *check.C) { - testServer.Response(200, nil, "content") - - b := s.s3.Bucket("bucket") - rc, err := b.GetReader("name") - c.Assert(err, check.IsNil) - data, err := ioutil.ReadAll(rc) - rc.Close() - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "content") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") -} - -func (s *S) TestGetNotFound(c *check.C) { - for i := 0; i < 10; i++ { - testServer.Response(404, nil, GetObjectErrorDump) - } - - b := s.s3.Bucket("non-existent-bucket") - data, err := b.Get("non-existent") - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/non-existent-bucket/non-existent") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - - s3err, _ := err.(*s3.Error) - c.Assert(s3err, check.NotNil) - c.Assert(s3err.StatusCode, check.Equals, 404) - c.Assert(s3err.BucketName, check.Equals, "non-existent-bucket") - c.Assert(s3err.RequestId, check.Equals, "3F1B667FAD71C3D8") - c.Assert(s3err.HostId, check.Equals, "L4ee/zrm1irFXY5F45fKXIRdOf9ktsKY/8TDVawuMK2jWRb1RF84i1uBzkdNqS5D") - c.Assert(s3err.Code, check.Equals, "NoSuchBucket") - c.Assert(s3err.Message, check.Equals, "The specified bucket does not exist") - c.Assert(s3err.Error(), check.Equals, "The specified bucket does not exist") - c.Assert(data, check.IsNil) -} - -// PutObject docs: http://goo.gl/FEBPD - -func (s *S) TestPutObject(c *check.C) { - testServer.Response(200, nil, "") - const DISPOSITION = "attachment; filename=\"0x1a2b3c.jpg\"" - - b := s.s3.Bucket("bucket") - err := b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{ContentDisposition: DISPOSITION}) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.DeepEquals), []string{""}) - c.Assert(req.Header["Content-Type"], check.DeepEquals, []string{"content-type"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"7"}) - c.Assert(req.Header["Content-Disposition"], check.DeepEquals, []string{DISPOSITION}) - //c.Assert(req.Header["Content-MD5"], gocheck.DeepEquals, "...") - c.Assert(req.Header["X-Amz-Acl"], check.DeepEquals, []string{"private"}) -} - -// PutCopy docs: http://goo.gl/mhEHtA -func (s *S) TestPutCopy(c *check.C) { - testServer.Response(200, nil, PutCopyResultDump) - - b := s.s3.Bucket("bucket") - res, err := b.PutCopy("name", s3.Private, s3.CopyOptions{}, - // 0xFC is ü - 0xE9 is é - "source-bucket/\u00FCber-fil\u00E9.jpg") - c.Assert(err, check.IsNil) - c.Assert(res, check.DeepEquals, &s3.CopyObjectResult{ - ETag: `"9b2cf535f27731c974343645a3985328"`, - LastModified: `2009-10-28T22:32:00`}) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.DeepEquals), []string{""}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"0"}) - c.Assert(req.Header["X-Amz-Copy-Source"], check.DeepEquals, []string{`source-bucket%2F%C3%BCber-fil%C3%A9.jpg`}) - c.Assert(req.Header["X-Amz-Acl"], check.DeepEquals, []string{"private"}) -} - -func (s *S) TestPutObjectReadTimeout(c *check.C) { - s.s3.ReadTimeout = 50 * time.Millisecond - defer func() { - s.s3.ReadTimeout = 0 - }() - - b := s.s3.Bucket("bucket") - err := b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{}) - - // Make sure that we get a timeout error. - c.Assert(err, check.NotNil) - - // Set the response after the request times out so that the next request will work. - testServer.Response(200, nil, "") - - // This time set the response within our timeout period so that we expect the call - // to return successfully. - go func() { - time.Sleep(25 * time.Millisecond) - testServer.Response(200, nil, "") - }() - err = b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) -} - -func (s *S) TestPutReader(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - buf := bytes.NewBufferString("content") - err := b.PutReader("name", buf, int64(buf.Len()), "content-type", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "PUT") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.DeepEquals), []string{""}) - c.Assert(req.Header["Content-Type"], check.DeepEquals, []string{"content-type"}) - c.Assert(req.Header["Content-Length"], check.DeepEquals, []string{"7"}) - //c.Assert(req.Header["Content-MD5"], gocheck.Equals, "...") - c.Assert(req.Header["X-Amz-Acl"], check.DeepEquals, []string{"private"}) -} - -// DelObject docs: http://goo.gl/APeTt - -func (s *S) TestDelObject(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - err := b.Del("name") - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "DELETE") - c.Assert(req.URL.Path, check.Equals, "/bucket/name") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") -} - -func (s *S) TestDelMultiObjects(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - objects := []s3.Object{s3.Object{Key: "test"}} - err := b.DelMulti(s3.Delete{ - Quiet: false, - Objects: objects, - }) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "POST") - c.Assert(req.URL.RawQuery, check.Equals, "delete=") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - c.Assert(req.Header["Content-MD5"], check.Not(check.Equals), "") - c.Assert(req.Header["Content-Type"], check.Not(check.Equals), "") - c.Assert(req.ContentLength, check.Not(check.Equals), "") -} - -// Bucket List Objects docs: http://goo.gl/YjQTc - -func (s *S) TestList(c *check.C) { - testServer.Response(200, nil, GetListResultDump1) - - b := s.s3.Bucket("quotes") - - data, err := b.List("N", "", "", 0) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/quotes/") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - c.Assert(req.Form["prefix"], check.DeepEquals, []string{"N"}) - c.Assert(req.Form["delimiter"], check.DeepEquals, []string{""}) - c.Assert(req.Form["marker"], check.DeepEquals, []string{""}) - c.Assert(req.Form["max-keys"], check.DeepEquals, []string(nil)) - - c.Assert(data.Name, check.Equals, "quotes") - c.Assert(data.Prefix, check.Equals, "N") - c.Assert(data.IsTruncated, check.Equals, false) - c.Assert(len(data.Contents), check.Equals, 2) - - c.Assert(data.Contents[0].Key, check.Equals, "Nelson") - c.Assert(data.Contents[0].LastModified, check.Equals, "2006-01-01T12:00:00.000Z") - c.Assert(data.Contents[0].ETag, check.Equals, `"828ef3fdfa96f00ad9f27c383fc9ac7f"`) - c.Assert(data.Contents[0].Size, check.Equals, int64(5)) - c.Assert(data.Contents[0].StorageClass, check.Equals, "STANDARD") - c.Assert(data.Contents[0].Owner.ID, check.Equals, "bcaf161ca5fb16fd081034f") - c.Assert(data.Contents[0].Owner.DisplayName, check.Equals, "webfile") - - c.Assert(data.Contents[1].Key, check.Equals, "Neo") - c.Assert(data.Contents[1].LastModified, check.Equals, "2006-01-01T12:00:00.000Z") - c.Assert(data.Contents[1].ETag, check.Equals, `"828ef3fdfa96f00ad9f27c383fc9ac7f"`) - c.Assert(data.Contents[1].Size, check.Equals, int64(4)) - c.Assert(data.Contents[1].StorageClass, check.Equals, "STANDARD") - c.Assert(data.Contents[1].Owner.ID, check.Equals, "bcaf1ffd86a5fb16fd081034f") - c.Assert(data.Contents[1].Owner.DisplayName, check.Equals, "webfile") -} - -func (s *S) TestListWithDelimiter(c *check.C) { - testServer.Response(200, nil, GetListResultDump2) - - b := s.s3.Bucket("quotes") - - data, err := b.List("photos/2006/", "/", "some-marker", 1000) - c.Assert(err, check.IsNil) - - req := testServer.WaitRequest() - c.Assert(req.Method, check.Equals, "GET") - c.Assert(req.URL.Path, check.Equals, "/quotes/") - c.Assert(req.Header["Date"], check.Not(check.Equals), "") - c.Assert(req.Form["prefix"], check.DeepEquals, []string{"photos/2006/"}) - c.Assert(req.Form["delimiter"], check.DeepEquals, []string{"/"}) - c.Assert(req.Form["marker"], check.DeepEquals, []string{"some-marker"}) - c.Assert(req.Form["max-keys"], check.DeepEquals, []string{"1000"}) - - c.Assert(data.Name, check.Equals, "example-bucket") - c.Assert(data.Prefix, check.Equals, "photos/2006/") - c.Assert(data.Delimiter, check.Equals, "/") - c.Assert(data.Marker, check.Equals, "some-marker") - c.Assert(data.IsTruncated, check.Equals, false) - c.Assert(len(data.Contents), check.Equals, 0) - c.Assert(data.CommonPrefixes, check.DeepEquals, []string{"photos/2006/feb/", "photos/2006/jan/"}) -} - -func (s *S) TestExists(c *check.C) { - testServer.Response(200, nil, "") - - b := s.s3.Bucket("bucket") - result, err := b.Exists("name") - - req := testServer.WaitRequest() - - c.Assert(req.Method, check.Equals, "HEAD") - - c.Assert(err, check.IsNil) - c.Assert(result, check.Equals, true) -} - -func (s *S) TestExistsNotFound404(c *check.C) { - testServer.Response(404, nil, "") - - b := s.s3.Bucket("bucket") - result, err := b.Exists("name") - - req := testServer.WaitRequest() - - c.Assert(req.Method, check.Equals, "HEAD") - - c.Assert(err, check.IsNil) - c.Assert(result, check.Equals, false) -} - -func (s *S) TestExistsNotFound403(c *check.C) { - testServer.Response(403, nil, "") - - b := s.s3.Bucket("bucket") - result, err := b.Exists("name") - - req := testServer.WaitRequest() - - c.Assert(req.Method, check.Equals, "HEAD") - - c.Assert(err, check.IsNil) - c.Assert(result, check.Equals, false) -} - -func (s *S) TestGetService(c *check.C) { - testServer.Response(200, nil, GetServiceDump) - - expected := s3.GetServiceResp{ - Owner: s3.Owner{ - ID: "bcaf1ffd86f461ca5fb16fd081034f", - DisplayName: "webfile", - }, - Buckets: []s3.BucketInfo{ - s3.BucketInfo{ - Name: "quotes", - CreationDate: "2006-02-03T16:45:09.000Z", - }, - s3.BucketInfo{ - Name: "samples", - CreationDate: "2006-02-03T16:41:58.000Z", - }, - }, - } - - received, err := s.s3.GetService() - - c.Assert(err, check.IsNil) - c.Assert(*received, check.DeepEquals, expected) -} - -func (s *S) TestLocation(c *check.C) { - testServer.Response(200, nil, GetLocationUsStandard) - expectedUsStandard := "us-east-1" - - bucketUsStandard := s.s3.Bucket("us-east-1") - resultUsStandard, err := bucketUsStandard.Location() - - c.Assert(err, check.IsNil) - c.Assert(resultUsStandard, check.Equals, expectedUsStandard) - - testServer.Response(200, nil, GetLocationUsWest1) - expectedUsWest1 := "us-west-1" - - bucketUsWest1 := s.s3.Bucket("us-west-1") - resultUsWest1, err := bucketUsWest1.Location() - - c.Assert(err, check.IsNil) - c.Assert(resultUsWest1, check.Equals, expectedUsWest1) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3i_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3i_test.go deleted file mode 100644 index 34c144b7c..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3i_test.go +++ /dev/null @@ -1,589 +0,0 @@ -package s3_test - -import ( - "bytes" - "crypto/md5" - "fmt" - "github.com/crowdmob/goamz/testutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "gopkg.in/check.v1" - "io/ioutil" - "net" - "net/http" - "sort" - "strings" - "time" -) - -// AmazonServer represents an Amazon S3 server. -type AmazonServer struct { - auth aws.Auth -} - -func (s *AmazonServer) SetUp(c *check.C) { - auth, err := aws.EnvAuth() - if err != nil { - c.Fatal(err.Error()) - } - s.auth = auth -} - -var _ = check.Suite(&AmazonClientSuite{Region: aws.USEast}) -var _ = check.Suite(&AmazonClientSuite{Region: aws.EUWest}) -var _ = check.Suite(&AmazonDomainClientSuite{Region: aws.USEast}) - -// AmazonClientSuite tests the client against a live S3 server. -type AmazonClientSuite struct { - aws.Region - srv AmazonServer - ClientTests -} - -func (s *AmazonClientSuite) SetUpSuite(c *check.C) { - if !testutil.Amazon { - c.Skip("live tests against AWS disabled (no -amazon)") - } - s.srv.SetUp(c) - s.s3 = s3.New(s.srv.auth, s.Region) - // In case tests were interrupted in the middle before. - s.ClientTests.Cleanup() -} - -func (s *AmazonClientSuite) TearDownTest(c *check.C) { - s.ClientTests.Cleanup() -} - -// AmazonDomainClientSuite tests the client against a live S3 -// server using bucket names in the endpoint domain name rather -// than the request path. -type AmazonDomainClientSuite struct { - aws.Region - srv AmazonServer - ClientTests -} - -func (s *AmazonDomainClientSuite) SetUpSuite(c *check.C) { - if !testutil.Amazon { - c.Skip("live tests against AWS disabled (no -amazon)") - } - s.srv.SetUp(c) - region := s.Region - region.S3BucketEndpoint = "https://${bucket}.s3.amazonaws.com" - s.s3 = s3.New(s.srv.auth, region) - s.ClientTests.Cleanup() -} - -func (s *AmazonDomainClientSuite) TearDownTest(c *check.C) { - s.ClientTests.Cleanup() -} - -// ClientTests defines integration tests designed to test the client. -// It is not used as a test suite in itself, but embedded within -// another type. -type ClientTests struct { - s3 *s3.S3 - authIsBroken bool -} - -func (s *ClientTests) Cleanup() { - killBucket(testBucket(s.s3)) -} - -func testBucket(s *s3.S3) *s3.Bucket { - // Watch out! If this function is corrupted and made to match with something - // people own, killBucket will happily remove *everything* inside the bucket. - key := s.Auth.AccessKey - if len(key) >= 8 { - key = s.Auth.AccessKey[:8] - } - return s.Bucket(fmt.Sprintf("goamz-%s-%s", s.Region.Name, key)) -} - -var attempts = aws.AttemptStrategy{ - Min: 5, - Total: 20 * time.Second, - Delay: 100 * time.Millisecond, -} - -func killBucket(b *s3.Bucket) { - var err error - for attempt := attempts.Start(); attempt.Next(); { - err = b.DelBucket() - if err == nil { - return - } - if _, ok := err.(*net.DNSError); ok { - return - } - e, ok := err.(*s3.Error) - if ok && e.Code == "NoSuchBucket" { - return - } - if ok && e.Code == "BucketNotEmpty" { - // Errors are ignored here. Just retry. - resp, err := b.List("", "", "", 1000) - if err == nil { - for _, key := range resp.Contents { - _ = b.Del(key.Key) - } - } - multis, _, _ := b.ListMulti("", "") - for _, m := range multis { - _ = m.Abort() - } - } - } - message := "cannot delete test bucket" - if err != nil { - message += ": " + err.Error() - } - panic(message) -} - -func get(url string) ([]byte, error) { - for attempt := attempts.Start(); attempt.Next(); { - resp, err := http.Get(url) - if err != nil { - if attempt.HasNext() { - continue - } - return nil, err - } - data, err := ioutil.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - if attempt.HasNext() { - continue - } - return nil, err - } - return data, err - } - panic("unreachable") -} - -func (s *ClientTests) TestBasicFunctionality(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.PublicRead) - c.Assert(err, check.IsNil) - - err = b.Put("name", []byte("yo!"), "text/plain", s3.PublicRead, s3.Options{}) - c.Assert(err, check.IsNil) - defer b.Del("name") - - data, err := b.Get("name") - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "yo!") - - data, err = get(b.URL("name")) - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "yo!") - - buf := bytes.NewBufferString("hey!") - err = b.PutReader("name2", buf, int64(buf.Len()), "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - defer b.Del("name2") - - rc, err := b.GetReader("name2") - c.Assert(err, check.IsNil) - data, err = ioutil.ReadAll(rc) - c.Check(err, check.IsNil) - c.Check(string(data), check.Equals, "hey!") - rc.Close() - - data, err = get(b.SignedURL("name2", time.Now().Add(time.Hour))) - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Equals, "hey!") - - if !s.authIsBroken { - data, err = get(b.SignedURL("name2", time.Now().Add(-time.Hour))) - c.Assert(err, check.IsNil) - c.Assert(string(data), check.Matches, "(?s).*AccessDenied.*") - } - - err = b.DelBucket() - c.Assert(err, check.NotNil) - - s3err, ok := err.(*s3.Error) - c.Assert(ok, check.Equals, true) - c.Assert(s3err.Code, check.Equals, "BucketNotEmpty") - c.Assert(s3err.BucketName, check.Equals, b.Name) - c.Assert(s3err.Message, check.Equals, "The bucket you tried to delete is not empty") - - err = b.Del("name") - c.Assert(err, check.IsNil) - err = b.Del("name2") - c.Assert(err, check.IsNil) - - err = b.DelBucket() - c.Assert(err, check.IsNil) -} - -func (s *ClientTests) TestGetNotFound(c *check.C) { - b := s.s3.Bucket("goamz-" + s.s3.Auth.AccessKey) - data, err := b.Get("non-existent") - - s3err, _ := err.(*s3.Error) - c.Assert(s3err, check.NotNil) - c.Assert(s3err.StatusCode, check.Equals, 404) - c.Assert(s3err.Code, check.Equals, "NoSuchBucket") - c.Assert(s3err.Message, check.Equals, "The specified bucket does not exist") - c.Assert(data, check.IsNil) -} - -// Communicate with all endpoints to see if they are alive. -func (s *ClientTests) TestRegions(c *check.C) { - errs := make(chan error, len(aws.Regions)) - for _, region := range aws.Regions { - go func(r aws.Region) { - s := s3.New(s.s3.Auth, r) - b := s.Bucket("goamz-" + s.Auth.AccessKey) - _, err := b.Get("non-existent") - errs <- err - }(region) - } - for _ = range aws.Regions { - err := <-errs - if err != nil { - s3_err, ok := err.(*s3.Error) - if ok { - c.Check(s3_err.Code, check.Matches, "NoSuchBucket") - } else if _, ok = err.(*net.DNSError); ok { - // Okay as well. - } else { - c.Errorf("Non-S3 error: %s", err) - } - } else { - c.Errorf("Test should have errored but it seems to have succeeded") - } - } -} - -var objectNames = []string{ - "index.html", - "index2.html", - "photos/2006/February/sample2.jpg", - "photos/2006/February/sample3.jpg", - "photos/2006/February/sample4.jpg", - "photos/2006/January/sample.jpg", - "test/bar", - "test/foo", -} - -func keys(names ...string) []s3.Key { - ks := make([]s3.Key, len(names)) - for i, name := range names { - ks[i].Key = name - } - return ks -} - -// As the ListResp specifies all the parameters to the -// request too, we use it to specify request parameters -// and expected results. The Contents field is -// used only for the key names inside it. -var listTests = []s3.ListResp{ - // normal list. - { - Contents: keys(objectNames...), - }, { - Marker: objectNames[0], - Contents: keys(objectNames[1:]...), - }, { - Marker: objectNames[0] + "a", - Contents: keys(objectNames[1:]...), - }, { - Marker: "z", - }, - - // limited results. - { - MaxKeys: 2, - Contents: keys(objectNames[0:2]...), - IsTruncated: true, - }, { - MaxKeys: 2, - Marker: objectNames[0], - Contents: keys(objectNames[1:3]...), - IsTruncated: true, - }, { - MaxKeys: 2, - Marker: objectNames[len(objectNames)-2], - Contents: keys(objectNames[len(objectNames)-1:]...), - }, - - // with delimiter - { - Delimiter: "/", - CommonPrefixes: []string{"photos/", "test/"}, - Contents: keys("index.html", "index2.html"), - }, { - Delimiter: "/", - Prefix: "photos/2006/", - CommonPrefixes: []string{"photos/2006/February/", "photos/2006/January/"}, - }, { - Delimiter: "/", - Prefix: "t", - CommonPrefixes: []string{"test/"}, - }, { - Delimiter: "/", - MaxKeys: 1, - Contents: keys("index.html"), - IsTruncated: true, - }, { - Delimiter: "/", - MaxKeys: 1, - Marker: "index2.html", - CommonPrefixes: []string{"photos/"}, - IsTruncated: true, - }, { - Delimiter: "/", - MaxKeys: 1, - Marker: "photos/", - CommonPrefixes: []string{"test/"}, - IsTruncated: false, - }, { - Delimiter: "Feb", - CommonPrefixes: []string{"photos/2006/Feb"}, - Contents: keys("index.html", "index2.html", "photos/2006/January/sample.jpg", "test/bar", "test/foo"), - }, -} - -func (s *ClientTests) TestDoublePutBucket(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.PublicRead) - c.Assert(err, check.IsNil) - - err = b.PutBucket(s3.PublicRead) - if err != nil { - c.Assert(err, check.FitsTypeOf, new(s3.Error)) - c.Assert(err.(*s3.Error).Code, check.Equals, "BucketAlreadyOwnedByYou") - } -} - -func (s *ClientTests) TestBucketList(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - objData := make(map[string][]byte) - for i, path := range objectNames { - data := []byte(strings.Repeat("a", i)) - err := b.Put(path, data, "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - defer b.Del(path) - objData[path] = data - } - - for i, t := range listTests { - c.Logf("test %d", i) - resp, err := b.List(t.Prefix, t.Delimiter, t.Marker, t.MaxKeys) - c.Assert(err, check.IsNil) - c.Check(resp.Name, check.Equals, b.Name) - c.Check(resp.Delimiter, check.Equals, t.Delimiter) - c.Check(resp.IsTruncated, check.Equals, t.IsTruncated) - c.Check(resp.CommonPrefixes, check.DeepEquals, t.CommonPrefixes) - checkContents(c, resp.Contents, objData, t.Contents) - } -} - -func etag(data []byte) string { - sum := md5.New() - sum.Write(data) - return fmt.Sprintf(`"%x"`, sum.Sum(nil)) -} - -func checkContents(c *check.C, contents []s3.Key, data map[string][]byte, expected []s3.Key) { - c.Assert(contents, check.HasLen, len(expected)) - for i, k := range contents { - c.Check(k.Key, check.Equals, expected[i].Key) - // TODO mtime - c.Check(k.Size, check.Equals, int64(len(data[k.Key]))) - c.Check(k.ETag, check.Equals, etag(data[k.Key])) - } -} - -func (s *ClientTests) TestMultiInitPutList(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - c.Assert(multi.UploadId, check.Matches, ".+") - defer multi.Abort() - - var sent []s3.Part - - for i := 0; i < 5; i++ { - p, err := multi.PutPart(i+1, strings.NewReader(fmt.Sprintf("", i+1))) - c.Assert(err, check.IsNil) - c.Assert(p.N, check.Equals, i+1) - c.Assert(p.Size, check.Equals, int64(8)) - c.Assert(p.ETag, check.Matches, ".+") - sent = append(sent, p) - } - - s3.SetListPartsMax(2) - - parts, err := multi.ListParts() - c.Assert(err, check.IsNil) - c.Assert(parts, check.HasLen, len(sent)) - for i := range parts { - c.Assert(parts[i].N, check.Equals, sent[i].N) - c.Assert(parts[i].Size, check.Equals, sent[i].Size) - c.Assert(parts[i].ETag, check.Equals, sent[i].ETag) - } - - err = multi.Complete(parts) - s3err, failed := err.(*s3.Error) - c.Assert(failed, check.Equals, true) - c.Assert(s3err.Code, check.Equals, "EntityTooSmall") - - err = multi.Abort() - c.Assert(err, check.IsNil) - _, err = multi.ListParts() - s3err, ok := err.(*s3.Error) - c.Assert(ok, check.Equals, true) - c.Assert(s3err.Code, check.Equals, "NoSuchUpload") -} - -// This may take a minute or more due to the minimum size accepted S3 -// on multipart upload parts. -func (s *ClientTests) TestMultiComplete(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - c.Assert(multi.UploadId, check.Matches, ".+") - defer multi.Abort() - - // Minimum size S3 accepts for all but the last part is 5MB. - data1 := make([]byte, 5*1024*1024) - data2 := []byte("") - - part1, err := multi.PutPart(1, bytes.NewReader(data1)) - c.Assert(err, check.IsNil) - part2, err := multi.PutPart(2, bytes.NewReader(data2)) - c.Assert(err, check.IsNil) - - // Purposefully reversed. The order requirement must be handled. - err = multi.Complete([]s3.Part{part2, part1}) - c.Assert(err, check.IsNil) - - data, err := b.Get("multi") - c.Assert(err, check.IsNil) - - c.Assert(len(data), check.Equals, len(data1)+len(data2)) - for i := range data1 { - if data[i] != data1[i] { - c.Fatalf("uploaded object at byte %d: want %d, got %d", data1[i], data[i]) - } - } - c.Assert(string(data[len(data1):]), check.Equals, string(data2)) -} - -type multiList []*s3.Multi - -func (l multiList) Len() int { return len(l) } -func (l multiList) Less(i, j int) bool { return l[i].Key < l[j].Key } -func (l multiList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -func (s *ClientTests) TestListMulti(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - // Ensure an empty state before testing its behavior. - multis, _, err := b.ListMulti("", "") - for _, m := range multis { - err := m.Abort() - c.Assert(err, check.IsNil) - } - - keys := []string{ - "a/multi2", - "a/multi3", - "b/multi4", - "multi1", - } - for _, key := range keys { - m, err := b.InitMulti(key, "", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - defer m.Abort() - } - - // Amazon's implementation of the multiple-request listing for - // multipart uploads in progress seems broken in multiple ways. - // (next tokens are not provided, etc). - //s3.SetListMultiMax(2) - - multis, prefixes, err := b.ListMulti("", "") - c.Assert(err, check.IsNil) - for attempt := attempts.Start(); attempt.Next() && len(multis) < len(keys); { - multis, prefixes, err = b.ListMulti("", "") - c.Assert(err, check.IsNil) - } - sort.Sort(multiList(multis)) - c.Assert(prefixes, check.IsNil) - var gotKeys []string - for _, m := range multis { - gotKeys = append(gotKeys, m.Key) - } - c.Assert(gotKeys, check.DeepEquals, keys) - for _, m := range multis { - c.Assert(m.Bucket, check.Equals, b) - c.Assert(m.UploadId, check.Matches, ".+") - } - - multis, prefixes, err = b.ListMulti("", "/") - for attempt := attempts.Start(); attempt.Next() && len(prefixes) < 2; { - multis, prefixes, err = b.ListMulti("", "") - c.Assert(err, check.IsNil) - } - c.Assert(err, check.IsNil) - c.Assert(prefixes, check.DeepEquals, []string{"a/", "b/"}) - c.Assert(multis, check.HasLen, 1) - c.Assert(multis[0].Bucket, check.Equals, b) - c.Assert(multis[0].Key, check.Equals, "multi1") - c.Assert(multis[0].UploadId, check.Matches, ".+") - - for attempt := attempts.Start(); attempt.Next() && len(multis) < 2; { - multis, prefixes, err = b.ListMulti("", "") - c.Assert(err, check.IsNil) - } - multis, prefixes, err = b.ListMulti("a/", "/") - c.Assert(err, check.IsNil) - c.Assert(prefixes, check.IsNil) - c.Assert(multis, check.HasLen, 2) - c.Assert(multis[0].Bucket, check.Equals, b) - c.Assert(multis[0].Key, check.Equals, "a/multi2") - c.Assert(multis[0].UploadId, check.Matches, ".+") - c.Assert(multis[1].Bucket, check.Equals, b) - c.Assert(multis[1].Key, check.Equals, "a/multi3") - c.Assert(multis[1].UploadId, check.Matches, ".+") -} - -func (s *ClientTests) TestMultiPutAllZeroLength(c *check.C) { - b := testBucket(s.s3) - err := b.PutBucket(s3.Private) - c.Assert(err, check.IsNil) - - multi, err := b.InitMulti("multi", "text/plain", s3.Private, s3.Options{}) - c.Assert(err, check.IsNil) - defer multi.Abort() - - // This tests an edge case. Amazon requires at least one - // part for multiprat uploads to work, even the part is empty. - parts, err := multi.PutAll(strings.NewReader(""), 5*1024*1024) - c.Assert(err, check.IsNil) - c.Assert(parts, check.HasLen, 1) - c.Assert(parts[0].Size, check.Equals, int64(0)) - c.Assert(parts[0].ETag, check.Equals, `"d41d8cd98f00b204e9800998ecf8427e"`) - - err = multi.Complete(parts) - c.Assert(err, check.IsNil) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3t_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3t_test.go deleted file mode 100644 index 8a5a4ff74..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3t_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package s3_test - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3test" - "gopkg.in/check.v1" -) - -type LocalServer struct { - auth aws.Auth - region aws.Region - srv *s3test.Server - config *s3test.Config -} - -func (s *LocalServer) SetUp(c *check.C) { - srv, err := s3test.NewServer(s.config) - c.Assert(err, check.IsNil) - c.Assert(srv, check.NotNil) - - s.srv = srv - s.region = aws.Region{ - Name: "faux-region-1", - S3Endpoint: srv.URL(), - S3LocationConstraint: true, // s3test server requires a LocationConstraint - } -} - -// LocalServerSuite defines tests that will run -// against the local s3test server. It includes -// selected tests from ClientTests; -// when the s3test functionality is sufficient, it should -// include all of them, and ClientTests can be simply embedded. -type LocalServerSuite struct { - srv LocalServer - clientTests ClientTests -} - -var ( - // run tests twice, once in us-east-1 mode, once not. - _ = check.Suite(&LocalServerSuite{}) - _ = check.Suite(&LocalServerSuite{ - srv: LocalServer{ - config: &s3test.Config{ - Send409Conflict: true, - }, - }, - }) -) - -func (s *LocalServerSuite) SetUpSuite(c *check.C) { - s.srv.SetUp(c) - s.clientTests.s3 = s3.New(s.srv.auth, s.srv.region) - - // TODO Sadly the fake server ignores auth completely right now. :-( - s.clientTests.authIsBroken = true - s.clientTests.Cleanup() -} - -func (s *LocalServerSuite) TearDownTest(c *check.C) { - s.clientTests.Cleanup() -} - -func (s *LocalServerSuite) TestBasicFunctionality(c *check.C) { - s.clientTests.TestBasicFunctionality(c) -} - -func (s *LocalServerSuite) TestGetNotFound(c *check.C) { - s.clientTests.TestGetNotFound(c) -} - -func (s *LocalServerSuite) TestBucketList(c *check.C) { - s.clientTests.TestBucketList(c) -} - -func (s *LocalServerSuite) TestDoublePutBucket(c *check.C) { - s.clientTests.TestDoublePutBucket(c) -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3test/server.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3test/server.go deleted file mode 100644 index 9b9b3c09c..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/s3test/server.go +++ /dev/null @@ -1,629 +0,0 @@ -package s3test - -import ( - "bytes" - "crypto/md5" - "encoding/base64" - "encoding/hex" - "encoding/xml" - "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "net/url" - "regexp" - "sort" - "strconv" - "strings" - "sync" - "time" -) - -const debug = false - -type s3Error struct { - statusCode int - XMLName struct{} `xml:"Error"` - Code string - Message string - BucketName string - RequestId string - HostId string -} - -type action struct { - srv *Server - w http.ResponseWriter - req *http.Request - reqId string -} - -// Config controls the internal behaviour of the Server. A nil config is the default -// and behaves as if all configurations assume their default behaviour. Once passed -// to NewServer, the configuration must not be modified. -type Config struct { - // Send409Conflict controls how the Server will respond to calls to PUT on a - // previously existing bucket. The default is false, and corresponds to the - // us-east-1 s3 enpoint. Setting this value to true emulates the behaviour of - // all other regions. - // http://docs.amazonwebservices.com/AmazonS3/latest/API/ErrorResponses.html - Send409Conflict bool -} - -func (c *Config) send409Conflict() bool { - if c != nil { - return c.Send409Conflict - } - return false -} - -// Server is a fake S3 server for testing purposes. -// All of the data for the server is kept in memory. -type Server struct { - url string - reqId int - listener net.Listener - mu sync.Mutex - buckets map[string]*bucket - config *Config -} - -type bucket struct { - name string - acl s3.ACL - ctime time.Time - objects map[string]*object -} - -type object struct { - name string - mtime time.Time - meta http.Header // metadata to return with requests. - checksum []byte // also held as Content-MD5 in meta. - data []byte -} - -// A resource encapsulates the subject of an HTTP request. -// The resource referred to may or may not exist -// when the request is made. -type resource interface { - put(a *action) interface{} - get(a *action) interface{} - post(a *action) interface{} - delete(a *action) interface{} -} - -func NewServer(config *Config) (*Server, error) { - l, err := net.Listen("tcp", "localhost:0") - if err != nil { - return nil, fmt.Errorf("cannot listen on localhost: %v", err) - } - srv := &Server{ - listener: l, - url: "http://" + l.Addr().String(), - buckets: make(map[string]*bucket), - config: config, - } - go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - srv.serveHTTP(w, req) - })) - return srv, nil -} - -// Quit closes down the server. -func (srv *Server) Quit() { - srv.listener.Close() -} - -// URL returns a URL for the server. -func (srv *Server) URL() string { - return srv.url -} - -func fatalf(code int, codeStr string, errf string, a ...interface{}) { - panic(&s3Error{ - statusCode: code, - Code: codeStr, - Message: fmt.Sprintf(errf, a...), - }) -} - -// serveHTTP serves the S3 protocol. -func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) { - // ignore error from ParseForm as it's usually spurious. - req.ParseForm() - - srv.mu.Lock() - defer srv.mu.Unlock() - - if debug { - log.Printf("s3test %q %q", req.Method, req.URL) - } - a := &action{ - srv: srv, - w: w, - req: req, - reqId: fmt.Sprintf("%09X", srv.reqId), - } - srv.reqId++ - - var r resource - defer func() { - switch err := recover().(type) { - case *s3Error: - switch r := r.(type) { - case objectResource: - err.BucketName = r.bucket.name - case bucketResource: - err.BucketName = r.name - } - err.RequestId = a.reqId - // TODO HostId - w.Header().Set("Content-Type", `xml version="1.0" encoding="UTF-8"`) - w.WriteHeader(err.statusCode) - xmlMarshal(w, err) - case nil: - default: - panic(err) - } - }() - - r = srv.resourceForURL(req.URL) - - var resp interface{} - switch req.Method { - case "PUT": - resp = r.put(a) - case "GET", "HEAD": - resp = r.get(a) - case "DELETE": - resp = r.delete(a) - case "POST": - resp = r.post(a) - default: - fatalf(400, "MethodNotAllowed", "unknown http request method %q", req.Method) - } - if resp != nil && req.Method != "HEAD" { - xmlMarshal(w, resp) - } -} - -// xmlMarshal is the same as xml.Marshal except that -// it panics on error. The marshalling should not fail, -// but we want to know if it does. -func xmlMarshal(w io.Writer, x interface{}) { - if err := xml.NewEncoder(w).Encode(x); err != nil { - panic(fmt.Errorf("error marshalling %#v: %v", x, err)) - } -} - -// In a fully implemented test server, each of these would have -// its own resource type. -var unimplementedBucketResourceNames = map[string]bool{ - "acl": true, - "lifecycle": true, - "policy": true, - "location": true, - "logging": true, - "notification": true, - "versions": true, - "requestPayment": true, - "versioning": true, - "website": true, - "uploads": true, -} - -var unimplementedObjectResourceNames = map[string]bool{ - "uploadId": true, - "acl": true, - "torrent": true, - "uploads": true, -} - -var pathRegexp = regexp.MustCompile("/(([^/]+)(/(.*))?)?") - -// resourceForURL returns a resource object for the given URL. -func (srv *Server) resourceForURL(u *url.URL) (r resource) { - m := pathRegexp.FindStringSubmatch(u.Path) - if m == nil { - fatalf(404, "InvalidURI", "Couldn't parse the specified URI") - } - bucketName := m[2] - objectName := m[4] - if bucketName == "" { - return nullResource{} // root - } - b := bucketResource{ - name: bucketName, - bucket: srv.buckets[bucketName], - } - q := u.Query() - if objectName == "" { - for name := range q { - if unimplementedBucketResourceNames[name] { - return nullResource{} - } - } - return b - - } - if b.bucket == nil { - fatalf(404, "NoSuchBucket", "The specified bucket does not exist") - } - objr := objectResource{ - name: objectName, - version: q.Get("versionId"), - bucket: b.bucket, - } - for name := range q { - if unimplementedObjectResourceNames[name] { - return nullResource{} - } - } - if obj := objr.bucket.objects[objr.name]; obj != nil { - objr.object = obj - } - return objr -} - -// nullResource has error stubs for all resource methods. -type nullResource struct{} - -func notAllowed() interface{} { - fatalf(400, "MethodNotAllowed", "The specified method is not allowed against this resource") - return nil -} - -func (nullResource) put(a *action) interface{} { return notAllowed() } -func (nullResource) get(a *action) interface{} { return notAllowed() } -func (nullResource) post(a *action) interface{} { return notAllowed() } -func (nullResource) delete(a *action) interface{} { return notAllowed() } - -const timeFormat = "2006-01-02T15:04:05.000Z07:00" - -type bucketResource struct { - name string - bucket *bucket // non-nil if the bucket already exists. -} - -// GET on a bucket lists the objects in the bucket. -// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html -func (r bucketResource) get(a *action) interface{} { - if r.bucket == nil { - fatalf(404, "NoSuchBucket", "The specified bucket does not exist") - } - delimiter := a.req.Form.Get("delimiter") - marker := a.req.Form.Get("marker") - maxKeys := -1 - if s := a.req.Form.Get("max-keys"); s != "" { - i, err := strconv.Atoi(s) - if err != nil || i < 0 { - fatalf(400, "invalid value for max-keys: %q", s) - } - maxKeys = i - } - prefix := a.req.Form.Get("prefix") - a.w.Header().Set("Content-Type", "application/xml") - - if a.req.Method == "HEAD" { - return nil - } - - var objs orderedObjects - - // first get all matching objects and arrange them in alphabetical order. - for name, obj := range r.bucket.objects { - if strings.HasPrefix(name, prefix) { - objs = append(objs, obj) - } - } - sort.Sort(objs) - - if maxKeys <= 0 { - maxKeys = 1000 - } - resp := &s3.ListResp{ - Name: r.bucket.name, - Prefix: prefix, - Delimiter: delimiter, - Marker: marker, - MaxKeys: maxKeys, - } - - var prefixes []string - for _, obj := range objs { - if !strings.HasPrefix(obj.name, prefix) { - continue - } - name := obj.name - isPrefix := false - if delimiter != "" { - if i := strings.Index(obj.name[len(prefix):], delimiter); i >= 0 { - name = obj.name[:len(prefix)+i+len(delimiter)] - if prefixes != nil && prefixes[len(prefixes)-1] == name { - continue - } - isPrefix = true - } - } - if name <= marker { - continue - } - if len(resp.Contents)+len(prefixes) >= maxKeys { - resp.IsTruncated = true - break - } - if isPrefix { - prefixes = append(prefixes, name) - } else { - // Contents contains only keys not found in CommonPrefixes - resp.Contents = append(resp.Contents, obj.s3Key()) - } - } - resp.CommonPrefixes = prefixes - return resp -} - -// orderedObjects holds a slice of objects that can be sorted -// by name. -type orderedObjects []*object - -func (s orderedObjects) Len() int { - return len(s) -} -func (s orderedObjects) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s orderedObjects) Less(i, j int) bool { - return s[i].name < s[j].name -} - -func (obj *object) s3Key() s3.Key { - return s3.Key{ - Key: obj.name, - LastModified: obj.mtime.Format(timeFormat), - Size: int64(len(obj.data)), - ETag: fmt.Sprintf(`"%x"`, obj.checksum), - // TODO StorageClass - // TODO Owner - } -} - -// DELETE on a bucket deletes the bucket if it's not empty. -func (r bucketResource) delete(a *action) interface{} { - b := r.bucket - if b == nil { - fatalf(404, "NoSuchBucket", "The specified bucket does not exist") - } - if len(b.objects) > 0 { - fatalf(400, "BucketNotEmpty", "The bucket you tried to delete is not empty") - } - delete(a.srv.buckets, b.name) - return nil -} - -// PUT on a bucket creates the bucket. -// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html -func (r bucketResource) put(a *action) interface{} { - var created bool - if r.bucket == nil { - if !validBucketName(r.name) { - fatalf(400, "InvalidBucketName", "The specified bucket is not valid") - } - if loc := locationConstraint(a); loc == "" { - fatalf(400, "InvalidRequets", "The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.") - } - // TODO validate acl - r.bucket = &bucket{ - name: r.name, - // TODO default acl - objects: make(map[string]*object), - } - a.srv.buckets[r.name] = r.bucket - created = true - } - if !created && a.srv.config.send409Conflict() { - fatalf(409, "BucketAlreadyOwnedByYou", "Your previous request to create the named bucket succeeded and you already own it.") - } - r.bucket.acl = s3.ACL(a.req.Header.Get("x-amz-acl")) - return nil -} - -func (bucketResource) post(a *action) interface{} { - fatalf(400, "Method", "bucket POST method not available") - return nil -} - -// validBucketName returns whether name is a valid bucket name. -// Here are the rules, from: -// http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/BucketRestrictions.html -// -// Can contain lowercase letters, numbers, periods (.), underscores (_), -// and dashes (-). You can use uppercase letters for buckets only in the -// US Standard region. -// -// Must start with a number or letter -// -// Must be between 3 and 255 characters long -// -// There's one extra rule (Must not be formatted as an IP address (e.g., 192.168.5.4) -// but the real S3 server does not seem to check that rule, so we will not -// check it either. -// -func validBucketName(name string) bool { - if len(name) < 3 || len(name) > 255 { - return false - } - r := name[0] - if !(r >= '0' && r <= '9' || r >= 'a' && r <= 'z') { - return false - } - for _, r := range name { - switch { - case r >= '0' && r <= '9': - case r >= 'a' && r <= 'z': - case r == '_' || r == '-': - case r == '.': - default: - return false - } - } - return true -} - -var responseParams = map[string]bool{ - "content-type": true, - "content-language": true, - "expires": true, - "cache-control": true, - "content-disposition": true, - "content-encoding": true, -} - -type objectResource struct { - name string - version string - bucket *bucket // always non-nil. - object *object // may be nil. -} - -// GET on an object gets the contents of the object. -// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html -func (objr objectResource) get(a *action) interface{} { - obj := objr.object - if obj == nil { - fatalf(404, "NoSuchKey", "The specified key does not exist.") - } - h := a.w.Header() - // add metadata - for name, d := range obj.meta { - h[name] = d - } - // override header values in response to request parameters. - for name, vals := range a.req.Form { - if strings.HasPrefix(name, "response-") { - name = name[len("response-"):] - if !responseParams[name] { - continue - } - h.Set(name, vals[0]) - } - } - if r := a.req.Header.Get("Range"); r != "" { - fatalf(400, "NotImplemented", "range unimplemented") - } - // TODO Last-Modified-Since - // TODO If-Modified-Since - // TODO If-Unmodified-Since - // TODO If-Match - // TODO If-None-Match - // TODO Connection: close ?? - // TODO x-amz-request-id - h.Set("Content-Length", fmt.Sprint(len(obj.data))) - h.Set("ETag", hex.EncodeToString(obj.checksum)) - h.Set("Last-Modified", obj.mtime.Format(time.RFC1123)) - if a.req.Method == "HEAD" { - return nil - } - // TODO avoid holding the lock when writing data. - _, err := a.w.Write(obj.data) - if err != nil { - // we can't do much except just log the fact. - log.Printf("error writing data: %v", err) - } - return nil -} - -var metaHeaders = map[string]bool{ - "Content-MD5": true, - "x-amz-acl": true, - "Content-Type": true, - "Content-Encoding": true, - "Content-Disposition": true, -} - -// PUT on an object creates the object. -func (objr objectResource) put(a *action) interface{} { - // TODO Cache-Control header - // TODO Expires header - // TODO x-amz-server-side-encryption - // TODO x-amz-storage-class - - // TODO is this correct, or should we erase all previous metadata? - obj := objr.object - if obj == nil { - obj = &object{ - name: objr.name, - meta: make(http.Header), - } - } - - var expectHash []byte - if c := a.req.Header.Get("Content-MD5"); c != "" { - var err error - expectHash, err = base64.StdEncoding.DecodeString(c) - if err != nil || len(expectHash) != md5.Size { - fatalf(400, "InvalidDigest", "The Content-MD5 you specified was invalid") - } - } - sum := md5.New() - // TODO avoid holding lock while reading data. - data, err := ioutil.ReadAll(io.TeeReader(a.req.Body, sum)) - if err != nil { - fatalf(400, "TODO", "read error") - } - gotHash := sum.Sum(nil) - if expectHash != nil && bytes.Compare(gotHash, expectHash) != 0 { - fatalf(400, "BadDigest", "The Content-MD5 you specified did not match what we received") - } - if a.req.ContentLength >= 0 && int64(len(data)) != a.req.ContentLength { - fatalf(400, "IncompleteBody", "You did not provide the number of bytes specified by the Content-Length HTTP header") - } - - // PUT request has been successful - save data and metadata - for key, values := range a.req.Header { - key = http.CanonicalHeaderKey(key) - if metaHeaders[key] || strings.HasPrefix(key, "X-Amz-Meta-") { - obj.meta[key] = values - } - } - obj.data = data - obj.checksum = gotHash - obj.mtime = time.Now() - objr.bucket.objects[objr.name] = obj - return nil -} - -func (objr objectResource) delete(a *action) interface{} { - delete(objr.bucket.objects, objr.name) - return nil -} - -func (objr objectResource) post(a *action) interface{} { - fatalf(400, "MethodNotAllowed", "The specified method is not allowed against this resource") - return nil -} - -type CreateBucketConfiguration struct { - LocationConstraint string -} - -// locationConstraint parses the request body (if present). -// If there is no body, an empty string will be returned. -func locationConstraint(a *action) string { - var body bytes.Buffer - if _, err := io.Copy(&body, a.req.Body); err != nil { - fatalf(400, "InvalidRequest", err.Error()) - } - if body.Len() == 0 { - return "" - } - var loc CreateBucketConfiguration - if err := xml.NewDecoder(&body).Decode(&loc); err != nil { - fatalf(400, "InvalidRequest", err.Error()) - } - return loc.LocationConstraint -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign.go deleted file mode 100644 index 3fce0b613..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign.go +++ /dev/null @@ -1,120 +0,0 @@ -package s3 - -import ( - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "log" - "sort" - "strings" -) - -var b64 = base64.StdEncoding - -// ---------------------------------------------------------------------------- -// S3 signing (http://goo.gl/G1LrK) - -var s3ParamsToSign = map[string]bool{ - "acl": true, - "location": true, - "logging": true, - "notification": true, - "partNumber": true, - "policy": true, - "requestPayment": true, - "torrent": true, - "uploadId": true, - "uploads": true, - "versionId": true, - "versioning": true, - "versions": true, - "response-content-type": true, - "response-content-language": true, - "response-expires": true, - "response-cache-control": true, - "response-content-disposition": true, - "response-content-encoding": true, - "website": true, - "delete": true, -} - -func sign(auth aws.Auth, method, canonicalPath string, params, headers map[string][]string) { - var md5, ctype, date, xamz string - var xamzDate bool - var keys, sarray []string - xheaders := make(map[string]string) - for k, v := range headers { - k = strings.ToLower(k) - switch k { - case "content-md5": - md5 = v[0] - case "content-type": - ctype = v[0] - case "date": - if !xamzDate { - date = v[0] - } - default: - if strings.HasPrefix(k, "x-amz-") { - keys = append(keys, k) - xheaders[k] = strings.Join(v, ",") - if k == "x-amz-date" { - xamzDate = true - date = "" - } - } - } - } - if len(keys) > 0 { - sort.StringSlice(keys).Sort() - for i := range keys { - key := keys[i] - value := xheaders[key] - sarray = append(sarray, key+":"+value) - } - xamz = strings.Join(sarray, "\n") + "\n" - } - - expires := false - if v, ok := params["Expires"]; ok { - // Query string request authentication alternative. - expires = true - date = v[0] - params["AWSAccessKeyId"] = []string{auth.AccessKey} - } - - sarray = sarray[0:0] - for k, v := range params { - if s3ParamsToSign[k] { - for _, vi := range v { - if vi == "" { - sarray = append(sarray, k) - } else { - // "When signing you do not encode these values." - sarray = append(sarray, k+"="+vi) - } - } - } - } - if len(sarray) > 0 { - sort.StringSlice(sarray).Sort() - canonicalPath = canonicalPath + "?" + strings.Join(sarray, "&") - } - - payload := method + "\n" + md5 + "\n" + ctype + "\n" + date + "\n" + xamz + canonicalPath - hash := hmac.New(sha1.New, []byte(auth.SecretKey)) - hash.Write([]byte(payload)) - signature := make([]byte, b64.EncodedLen(hash.Size())) - b64.Encode(signature, hash.Sum(nil)) - - if expires { - params["Signature"] = []string{string(signature)} - } else { - headers["Authorization"] = []string{"AWS " + auth.AccessKey + ":" + string(signature)} - } - if debug { - log.Printf("Signature payload: %q", payload) - log.Printf("Signature: %q", signature) - } -} diff --git a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign_test.go b/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign_test.go deleted file mode 100644 index 7d5efa9e5..000000000 --- a/Godeps/_workspace/src/github.com/crowdmob/goamz/s3/sign_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package s3_test - -import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - "gopkg.in/check.v1" -) - -// S3 ReST authentication docs: http://goo.gl/G1LrK - -var testAuth = aws.Auth{AccessKey: "0PN5J17HBGZHT7JJ3X82", SecretKey: "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"} - -func (s *S) TestSignExampleObjectGet(c *check.C) { - method := "GET" - path := "/johnsmith/photos/puppy.jpg" - headers := map[string][]string{ - "Host": {"johnsmith.s3.amazonaws.com"}, - "Date": {"Tue, 27 Mar 2007 19:36:42 +0000"}, - } - s3.Sign(testAuth, method, path, nil, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleObjectPut(c *check.C) { - method := "PUT" - path := "/johnsmith/photos/puppy.jpg" - headers := map[string][]string{ - "Host": {"johnsmith.s3.amazonaws.com"}, - "Date": {"Tue, 27 Mar 2007 21:15:45 +0000"}, - "Content-Type": {"image/jpeg"}, - "Content-Length": {"94328"}, - } - s3.Sign(testAuth, method, path, nil, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:hcicpDDvL9SsO6AkvxqmIWkmOuQ=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleList(c *check.C) { - method := "GET" - path := "/johnsmith/" - params := map[string][]string{ - "prefix": {"photos"}, - "max-keys": {"50"}, - "marker": {"puppy"}, - } - headers := map[string][]string{ - "Host": {"johnsmith.s3.amazonaws.com"}, - "Date": {"Tue, 27 Mar 2007 19:42:41 +0000"}, - "User-Agent": {"Mozilla/5.0"}, - } - s3.Sign(testAuth, method, path, params, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:jsRt/rhG+Vtp88HrYL706QhE4w4=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleFetch(c *check.C) { - method := "GET" - path := "/johnsmith/" - params := map[string][]string{ - "acl": {""}, - } - headers := map[string][]string{ - "Host": {"johnsmith.s3.amazonaws.com"}, - "Date": {"Tue, 27 Mar 2007 19:44:46 +0000"}, - } - s3.Sign(testAuth, method, path, params, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:thdUi9VAkzhkniLj96JIrOPGi0g=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleDelete(c *check.C) { - method := "DELETE" - path := "/johnsmith/photos/puppy.jpg" - params := map[string][]string{} - headers := map[string][]string{ - "Host": {"s3.amazonaws.com"}, - "Date": {"Tue, 27 Mar 2007 21:20:27 +0000"}, - "User-Agent": {"dotnet"}, - "x-amz-date": {"Tue, 27 Mar 2007 21:20:26 +0000"}, - } - s3.Sign(testAuth, method, path, params, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:k3nL7gH3+PadhTEVn5Ip83xlYzk=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleUpload(c *check.C) { - method := "PUT" - path := "/static.johnsmith.net/db-backup.dat.gz" - params := map[string][]string{} - headers := map[string][]string{ - "Host": {"static.johnsmith.net:8080"}, - "Date": {"Tue, 27 Mar 2007 21:06:08 +0000"}, - "User-Agent": {"curl/7.15.5"}, - "x-amz-acl": {"public-read"}, - "content-type": {"application/x-download"}, - "Content-MD5": {"4gJE4saaMU4BqNR0kLY+lw=="}, - "X-Amz-Meta-ReviewedBy": {"joe@johnsmith.net,jane@johnsmith.net"}, - "X-Amz-Meta-FileChecksum": {"0x02661779"}, - "X-Amz-Meta-ChecksumAlgorithm": {"crc32"}, - "Content-Disposition": {"attachment; filename=database.dat"}, - "Content-Encoding": {"gzip"}, - "Content-Length": {"5913339"}, - } - s3.Sign(testAuth, method, path, params, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:C0FlOtU8Ylb9KDTpZqYkZPX91iI=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleListAllMyBuckets(c *check.C) { - method := "GET" - path := "/" - headers := map[string][]string{ - "Host": {"s3.amazonaws.com"}, - "Date": {"Wed, 28 Mar 2007 01:29:59 +0000"}, - } - s3.Sign(testAuth, method, path, nil, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:Db+gepJSUbZKwpx1FR0DLtEYoZA=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleUnicodeKeys(c *check.C) { - method := "GET" - path := "/dictionary/fran%C3%A7ais/pr%c3%a9f%c3%a8re" - headers := map[string][]string{ - "Host": {"s3.amazonaws.com"}, - "Date": {"Wed, 28 Mar 2007 01:49:49 +0000"}, - } - s3.Sign(testAuth, method, path, nil, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:dxhSBHoI6eVSPcXJqEghlUzZMnY=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} - -func (s *S) TestSignExampleCustomSSE(c *check.C) { - method := "GET" - path := "/secret/config" - params := map[string][]string{} - headers := map[string][]string{ - "Host": {"secret.johnsmith.net:8080"}, - "Date": {"Tue, 27 Mar 2007 21:06:08 +0000"}, - "x-amz-server-side-encryption-customer-key": {"MWJhakVna1dQT1B0SDFMeGtVVnRQRTFGaU1ldFJrU0I="}, - "x-amz-server-side-encryption-customer-key-MD5": {"glIqxpqQ4a9aoK/iLttKzQ=="}, - "x-amz-server-side-encryption-customer-algorithm": {"AES256"}, - } - s3.Sign(testAuth, method, path, params, headers) - expected := "AWS 0PN5J17HBGZHT7JJ3X82:Xq6PWmIo0aOWq+LDjCEiCGgbmHE=" - c.Assert(headers["Authorization"], check.DeepEquals, []string{expected}) -} diff --git a/Godeps/_workspace/src/github.com/fd/go-nat/LICENSE b/Godeps/_workspace/src/github.com/fd/go-nat/LICENSE deleted file mode 100644 index 37ec93a14..000000000 --- a/Godeps/_workspace/src/github.com/fd/go-nat/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Godeps/_workspace/src/github.com/fd/go-nat/README.md b/Godeps/_workspace/src/github.com/fd/go-nat/README.md deleted file mode 100644 index 24ddea09e..000000000 --- a/Godeps/_workspace/src/github.com/fd/go-nat/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# go-nat - -[![GoDoc](https://godoc.org/github.com/fd/go-nat?status.svg)](https://godoc.org/github.com/fd/go-nat) [![status](https://sourcegraph.com/api/repos/github.com/fd/go-nat/.badges/status.png)](https://sourcegraph.com/github.com/fd/go-nat) diff --git a/Godeps/_workspace/src/github.com/fd/go-nat/nat.go b/Godeps/_workspace/src/github.com/fd/go-nat/nat.go deleted file mode 100644 index 3cf964858..000000000 --- a/Godeps/_workspace/src/github.com/fd/go-nat/nat.go +++ /dev/null @@ -1,54 +0,0 @@ -// Package nat implements NAT handling facilities -package nat - -import ( - "errors" - "math" - "math/rand" - "net" - "time" -) - -var ErrNoExternalAddress = errors.New("no external address") -var ErrNoInternalAddress = errors.New("no internal address") -var ErrNoNATFound = errors.New("no NAT found") - -// protocol is either "udp" or "tcp" -type NAT interface { - // Type returns the kind of NAT port mapping service that is used - Type() string - - // GetDeviceAddress returns the internal address of the gateway device. - GetDeviceAddress() (addr net.IP, err error) - - // GetExternalAddress returns the external address of the gateway device. - GetExternalAddress() (addr net.IP, err error) - - // GetInternalAddress returns the address of the local host. - GetInternalAddress() (addr net.IP, err error) - - // AddPortMapping maps a port on the local host to an external port. - AddPortMapping(protocol string, internalPort int, description string, timeout time.Duration) (mappedExternalPort int, err error) - - // DeletePortMapping removes a port mapping. - DeletePortMapping(protocol string, internalPort int) (err error) -} - -// DiscoverGateway attempts to find a gateway device. -func DiscoverGateway() (NAT, error) { - select { - case nat := <-discoverUPNP_IG1(): - return nat, nil - case nat := <-discoverUPNP_IG2(): - return nat, nil - case nat := <-discoverNATPMP(): - return nat, nil - case <-time.After(10 * time.Second): - return nil, ErrNoNATFound - } -} - -func randomPort() int { - rand.Seed(time.Now().UnixNano()) - return rand.Intn(math.MaxUint16-10000) + 10000 -} diff --git a/Godeps/_workspace/src/github.com/fd/go-nat/natpmp.go b/Godeps/_workspace/src/github.com/fd/go-nat/natpmp.go deleted file mode 100644 index 9d5fb675f..000000000 --- a/Godeps/_workspace/src/github.com/fd/go-nat/natpmp.go +++ /dev/null @@ -1,178 +0,0 @@ -package nat - -import ( - "net" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp" -) - -var ( - _ NAT = (*natpmp_NAT)(nil) -) - -func natpmp_PotentialGateways() ([]net.IP, error) { - _, ipNet_10, err := net.ParseCIDR("10.0.0.0/8") - if err != nil { - panic(err) - } - - _, ipNet_172_16, err := net.ParseCIDR("172.16.0.0/12") - if err != nil { - panic(err) - } - - _, ipNet_192_168, err := net.ParseCIDR("192.168.0.0/16") - if err != nil { - panic(err) - } - - ifaces, err := net.Interfaces() - if err != nil { - return nil, err - } - - var ips []net.IP - - for _, iface := range ifaces { - addrs, err := iface.Addrs() - if err != nil { - return nil, err - } - - for _, addr := range addrs { - switch x := addr.(type) { - case *net.IPNet: - var ipNet *net.IPNet - if ipNet_10.Contains(x.IP) { - ipNet = ipNet_10 - } else if ipNet_172_16.Contains(x.IP) { - ipNet = ipNet_172_16 - } else if ipNet_192_168.Contains(x.IP) { - ipNet = ipNet_192_168 - } - - if ipNet != nil { - ip := x.IP.Mask(x.Mask) - ip = ip.To4() - if ip != nil { - ip[3] = ip[3] | 0x01 - ips = append(ips, ip) - } - } - } - } - } - - if len(ips) == 0 { - return nil, ErrNoNATFound - } - - return ips, nil -} - -func discoverNATPMP() <-chan NAT { - ips, err := natpmp_PotentialGateways() - if err != nil { - return nil - } - - res := make(chan NAT, len(ips)) - - for _, ip := range ips { - go discoverNATPMPWithAddr(res, ip) - } - - return res -} - -func discoverNATPMPWithAddr(c chan NAT, ip net.IP) { - client := natpmp.NewClient(ip) - _, err := client.GetExternalAddress() - if err != nil { - return - } - - c <- &natpmp_NAT{client, ip, make(map[int]int)} -} - -type natpmp_NAT struct { - c *natpmp.Client - gateway net.IP - ports map[int]int -} - -func (n *natpmp_NAT) GetDeviceAddress() (addr net.IP, err error) { - return n.gateway, nil -} - -func (n *natpmp_NAT) GetInternalAddress() (addr net.IP, err error) { - ifaces, err := net.Interfaces() - if err != nil { - return nil, err - } - - for _, iface := range ifaces { - addrs, err := iface.Addrs() - if err != nil { - return nil, err - } - - for _, addr := range addrs { - switch x := addr.(type) { - case *net.IPNet: - if x.Contains(n.gateway) { - return x.IP, nil - } - } - } - } - - return nil, ErrNoInternalAddress -} - -func (n *natpmp_NAT) GetExternalAddress() (addr net.IP, err error) { - res, err := n.c.GetExternalAddress() - if err != nil { - return nil, err - } - - d := res.ExternalIPAddress - return net.IPv4(d[0], d[1], d[2], d[3]), nil -} - -func (n *natpmp_NAT) AddPortMapping(protocol string, internalPort int, description string, timeout time.Duration) (int, error) { - var ( - err error - ) - - timeoutInSeconds := int(timeout / time.Second) - - if externalPort := n.ports[internalPort]; externalPort > 0 { - _, err = n.c.AddPortMapping(protocol, internalPort, externalPort, timeoutInSeconds) - if err == nil { - n.ports[internalPort] = externalPort - return externalPort, nil - } - } - - for i := 0; i < 3; i++ { - externalPort := randomPort() - _, err = n.c.AddPortMapping(protocol, internalPort, externalPort, timeoutInSeconds) - if err == nil { - n.ports[internalPort] = externalPort - return externalPort, nil - } - } - - return 0, err -} - -func (n *natpmp_NAT) DeletePortMapping(protocol string, internalPort int) (err error) { - delete(n.ports, internalPort) - return nil -} - -func (n *natpmp_NAT) Type() string { - return "NAT-PMP" -} diff --git a/Godeps/_workspace/src/github.com/fd/go-nat/upnp.go b/Godeps/_workspace/src/github.com/fd/go-nat/upnp.go deleted file mode 100644 index 74936a8c7..000000000 --- a/Godeps/_workspace/src/github.com/fd/go-nat/upnp.go +++ /dev/null @@ -1,239 +0,0 @@ -package nat - -import ( - "net" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2" -) - -var ( - _ NAT = (*upnp_NAT)(nil) -) - -func discoverUPNP_IG1() <-chan NAT { - res := make(chan NAT, 1) - go func() { - - // find devices - devs, err := goupnp.DiscoverDevices(internetgateway1.URN_WANConnectionDevice_1) - if err != nil { - return - } - - for _, dev := range devs { - if dev.Root == nil { - continue - } - - dev.Root.Device.VisitServices(func(srv *goupnp.Service) { - switch srv.ServiceType { - case internetgateway1.URN_WANIPConnection_1: - client := &internetgateway1.WANIPConnection1{ServiceClient: goupnp.ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: dev.Root, - Service: srv, - }} - _, isNat, err := client.GetNATRSIPStatus() - if err == nil && isNat { - res <- &upnp_NAT{client, make(map[int]int), "UPNP (IG1-IP1)", dev.Root} - return - } - - case internetgateway1.URN_WANPPPConnection_1: - client := &internetgateway1.WANPPPConnection1{ServiceClient: goupnp.ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: dev.Root, - Service: srv, - }} - _, isNat, err := client.GetNATRSIPStatus() - if err == nil && isNat { - res <- &upnp_NAT{client, make(map[int]int), "UPNP (IG1-PPP1)", dev.Root} - return - } - - } - }) - } - - }() - return res -} - -func discoverUPNP_IG2() <-chan NAT { - res := make(chan NAT, 1) - go func() { - - // find devices - devs, err := goupnp.DiscoverDevices(internetgateway2.URN_WANConnectionDevice_2) - if err != nil { - return - } - - for _, dev := range devs { - if dev.Root == nil { - continue - } - - dev.Root.Device.VisitServices(func(srv *goupnp.Service) { - switch srv.ServiceType { - case internetgateway2.URN_WANIPConnection_1: - client := &internetgateway2.WANIPConnection1{ServiceClient: goupnp.ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: dev.Root, - Service: srv, - }} - _, isNat, err := client.GetNATRSIPStatus() - if err == nil && isNat { - res <- &upnp_NAT{client, make(map[int]int), "UPNP (IG2-IP1)", dev.Root} - return - } - - case internetgateway2.URN_WANIPConnection_2: - client := &internetgateway2.WANIPConnection2{ServiceClient: goupnp.ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: dev.Root, - Service: srv, - }} - _, isNat, err := client.GetNATRSIPStatus() - if err == nil && isNat { - res <- &upnp_NAT{client, make(map[int]int), "UPNP (IG2-IP2)", dev.Root} - return - } - - case internetgateway2.URN_WANPPPConnection_1: - client := &internetgateway2.WANPPPConnection1{ServiceClient: goupnp.ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: dev.Root, - Service: srv, - }} - _, isNat, err := client.GetNATRSIPStatus() - if err == nil && isNat { - res <- &upnp_NAT{client, make(map[int]int), "UPNP (IG2-PPP1)", dev.Root} - return - } - - } - }) - } - - }() - return res -} - -type upnp_NAT_Client interface { - GetExternalIPAddress() (string, error) - AddPortMapping(string, uint16, string, uint16, string, bool, string, uint32) error - DeletePortMapping(string, uint16, string) error -} - -type upnp_NAT struct { - c upnp_NAT_Client - ports map[int]int - typ string - rootDevice *goupnp.RootDevice -} - -func (u *upnp_NAT) GetExternalAddress() (addr net.IP, err error) { - ipString, err := u.c.GetExternalIPAddress() - if err != nil { - return nil, err - } - - ip := net.ParseIP(ipString) - if ip == nil { - return nil, ErrNoExternalAddress - } - - return ip, nil -} - -func mapProtocol(s string) string { - switch s { - case "udp": - return "UDP" - case "tcp": - return "TCP" - default: - panic("invalid protocol: " + s) - } -} - -func (u *upnp_NAT) AddPortMapping(protocol string, internalPort int, description string, timeout time.Duration) (int, error) { - ip, err := u.GetInternalAddress() - if err != nil { - return 0, nil - } - - timeoutInSeconds := uint32(timeout / time.Second) - - if externalPort := u.ports[internalPort]; externalPort > 0 { - err = u.c.AddPortMapping("", uint16(externalPort), mapProtocol(protocol), uint16(internalPort), ip.String(), true, description, timeoutInSeconds) - if err == nil { - return externalPort, nil - } - } - - for i := 0; i < 3; i++ { - externalPort := randomPort() - err = u.c.AddPortMapping("", uint16(externalPort), mapProtocol(protocol), uint16(internalPort), ip.String(), true, description, timeoutInSeconds) - if err == nil { - u.ports[internalPort] = externalPort - return externalPort, nil - } - } - - return 0, err -} - -func (u *upnp_NAT) DeletePortMapping(protocol string, internalPort int) error { - if externalPort := u.ports[internalPort]; externalPort > 0 { - delete(u.ports, internalPort) - return u.c.DeletePortMapping("", uint16(externalPort), mapProtocol(protocol)) - } - - return nil -} - -func (u *upnp_NAT) GetDeviceAddress() (net.IP, error) { - addr, err := net.ResolveUDPAddr("udp4", u.rootDevice.URLBase.Host) - if err != nil { - return nil, err - } - - return addr.IP, nil -} - -func (u *upnp_NAT) GetInternalAddress() (net.IP, error) { - devAddr, err := u.GetDeviceAddress() - if err != nil { - return nil, err - } - - ifaces, err := net.Interfaces() - if err != nil { - return nil, err - } - - for _, iface := range ifaces { - addrs, err := iface.Addrs() - if err != nil { - return nil, err - } - - for _, addr := range addrs { - switch x := addr.(type) { - case *net.IPNet: - if x.Contains(devAddr) { - return x.IP, nil - } - } - } - } - - return nil, ErrNoInternalAddress -} - -func (n *upnp_NAT) Type() string { return n.typ } diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/.gitignore b/Godeps/_workspace/src/github.com/hashicorp/yamux/.gitignore deleted file mode 100644 index 836562412..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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 diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/LICENSE b/Godeps/_workspace/src/github.com/hashicorp/yamux/LICENSE deleted file mode 100644 index f0e5c79e1..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/LICENSE +++ /dev/null @@ -1,362 +0,0 @@ -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. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/README.md b/Godeps/_workspace/src/github.com/hashicorp/yamux/README.md deleted file mode 100644 index d4db7fc99..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# Yamux - -Yamux (Yet another Multiplexer) is a multiplexing library for Golang. -It relies on an underlying connection to provide reliability -and ordering, such as TCP or Unix domain sockets, and provides -stream-oriented multiplexing. It is inspired by SPDY but is not -interoperable with it. - -Yamux features include: - -* Bi-directional streams - * Streams can be opened by either client or server - * Useful for NAT traversal - * Server-side push support -* Flow control - * Avoid starvation - * Back-pressure to prevent overwhelming a receiver -* Keep Alives - * Enables persistent connections over a load balancer -* Efficient - * Enables thousands of logical streams with low overhead - -## Documentation - -For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/yamux). - -## Specification - -The full specification for Yamux is provided in the `spec.md` file. -It can be used as a guide to implementors of interoperable libraries. - -## Usage - -Using Yamux is remarkably simple: - -```go - -func client() { - // Get a TCP connection - conn, err := net.Dial(...) - if err != nil { - panic(err) - } - - // Setup client side of yamux - session, err := yamux.Client(conn, nil) - if err != nil { - panic(err) - } - - // Open a new stream - stream, err := session.Open() - if err != nil { - panic(err) - } - - // Stream implements net.Conn - stream.Write([]byte("ping")) -} - -func server() { - // Accept a TCP connection - conn, err := listener.Accept() - if err != nil { - panic(err) - } - - // Setup server side of yamux - session, err := yamux.Server(conn, nil) - if err != nil { - panic(err) - } - - // Accept a stream - stream, err := session.Accept() - if err != nil { - panic(err) - } - - // Listen for a message - buf := make([]byte, 4) - stream.Read(buf) -} - -``` - diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/addr.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/addr.go deleted file mode 100644 index be6ebca9c..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/addr.go +++ /dev/null @@ -1,60 +0,0 @@ -package yamux - -import ( - "fmt" - "net" -) - -// hasAddr is used to get the address from the underlying connection -type hasAddr interface { - LocalAddr() net.Addr - RemoteAddr() net.Addr -} - -// yamuxAddr is used when we cannot get the underlying address -type yamuxAddr struct { - Addr string -} - -func (*yamuxAddr) Network() string { - return "yamux" -} - -func (y *yamuxAddr) String() string { - return fmt.Sprintf("yamux:%s", y.Addr) -} - -// Addr is used to get the address of the listener. -func (s *Session) Addr() net.Addr { - return s.LocalAddr() -} - -// LocalAddr is used to get the local address of the -// underlying connection. -func (s *Session) LocalAddr() net.Addr { - addr, ok := s.conn.(hasAddr) - if !ok { - return &yamuxAddr{"local"} - } - return addr.LocalAddr() -} - -// RemoteAddr is used to get the address of remote end -// of the underlying connection -func (s *Session) RemoteAddr() net.Addr { - addr, ok := s.conn.(hasAddr) - if !ok { - return &yamuxAddr{"remote"} - } - return addr.RemoteAddr() -} - -// LocalAddr returns the local address -func (s *Stream) LocalAddr() net.Addr { - return s.session.LocalAddr() -} - -// LocalAddr returns the remote address -func (s *Stream) RemoteAddr() net.Addr { - return s.session.RemoteAddr() -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/bench_test.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/bench_test.go deleted file mode 100644 index 4377b839c..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/bench_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package yamux - -import ( - "testing" -) - -func BenchmarkPing(b *testing.B) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - for i := 0; i < b.N; i++ { - rtt, err := client.Ping() - if err != nil { - b.Fatalf("err: %v", err) - } - if rtt == 0 { - b.Fatalf("bad: %v", rtt) - } - } -} - -func BenchmarkAccept(b *testing.B) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - go func() { - for i := 0; i < b.N; i++ { - stream, err := server.AcceptStream() - if err != nil { - return - } - stream.Close() - } - }() - - for i := 0; i < b.N; i++ { - stream, err := client.Open() - if err != nil { - b.Fatalf("err: %v", err) - } - stream.Close() - } -} - -func BenchmarkSendRecv(b *testing.B) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - sendBuf := make([]byte, 512) - recvBuf := make([]byte, 512) - - doneCh := make(chan struct{}) - go func() { - stream, err := server.AcceptStream() - if err != nil { - return - } - defer stream.Close() - for i := 0; i < b.N; i++ { - if _, err := stream.Read(recvBuf); err != nil { - b.Fatalf("err: %v", err) - } - } - close(doneCh) - }() - - stream, err := client.Open() - if err != nil { - b.Fatalf("err: %v", err) - } - defer stream.Close() - for i := 0; i < b.N; i++ { - if _, err := stream.Write(sendBuf); err != nil { - b.Fatalf("err: %v", err) - } - } - <-doneCh -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/const.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/const.go deleted file mode 100644 index 86dd4d1b7..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/const.go +++ /dev/null @@ -1,150 +0,0 @@ -package yamux - -import ( - "encoding/binary" - "fmt" -) - -var ( - // ErrInvalidVersion means we received a frame with an - // invalid version - ErrInvalidVersion = fmt.Errorf("invalid protocol version") - - // ErrInvalidMsgType means we received a frame with an - // invalid message type - ErrInvalidMsgType = fmt.Errorf("invalid msg type") - - // ErrSessionShutdown is used if there is a shutdown during - // an operation - ErrSessionShutdown = fmt.Errorf("session shutdown") - - // ErrStreamsExhausted is returned if we have no more - // stream ids to issue - ErrStreamsExhausted = fmt.Errorf("streams exhausted") - - // ErrDuplicateStream is used if a duplicate stream is - // opened inbound - ErrDuplicateStream = fmt.Errorf("duplicate stream initiated") - - // ErrReceiveWindowExceeded indicates the window was exceeded - ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded") - - // ErrTimeout is used when we reach an IO deadline - ErrTimeout = fmt.Errorf("i/o deadline reached") - - // ErrStreamClosed is returned when using a closed stream - ErrStreamClosed = fmt.Errorf("stream closed") - - // ErrUnexpectedFlag is set when we get an unexpected flag - ErrUnexpectedFlag = fmt.Errorf("unexpected flag") - - // ErrRemoteGoAway is used when we get a go away from the other side - ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections") - - // ErrConnectionReset is sent if a stream is reset. This can happen - // if the backlog is exceeded, or if there was a remote GoAway. - ErrConnectionReset = fmt.Errorf("connection reset") -) - -const ( - // protoVersion is the only version we support - protoVersion uint8 = 0 -) - -const ( - // Data is used for data frames. They are followed - // by length bytes worth of payload. - typeData uint8 = iota - - // WindowUpdate is used to change the window of - // a given stream. The length indicates the delta - // update to the window. - typeWindowUpdate - - // Ping is sent as a keep-alive or to measure - // the RTT. The StreamID and Length value are echoed - // back in the response. - typePing - - // GoAway is sent to terminate a session. The StreamID - // should be 0 and the length is an error code. - typeGoAway -) - -const ( - // SYN is sent to signal a new stream. May - // be sent with a data payload - flagSYN uint16 = 1 << iota - - // ACK is sent to acknowledge a new stream. May - // be sent with a data payload - flagACK - - // FIN is sent to half-close the given stream. - // May be sent with a data payload. - flagFIN - - // RST is used to hard close a given stream. - flagRST -) - -const ( - // initialStreamWindow is the initial stream window size - initialStreamWindow uint32 = 256 * 1024 -) - -const ( - // goAwayNormal is sent on a normal termination - goAwayNormal uint32 = iota - - // goAwayProtoErr sent on a protocol error - goAwayProtoErr - - // goAwayInternalErr sent on an internal error - goAwayInternalErr -) - -const ( - sizeOfVersion = 1 - sizeOfType = 1 - sizeOfFlags = 2 - sizeOfStreamID = 4 - sizeOfLength = 4 - headerSize = sizeOfVersion + sizeOfType + sizeOfFlags + - sizeOfStreamID + sizeOfLength -) - -type header []byte - -func (h header) Version() uint8 { - return h[0] -} - -func (h header) MsgType() uint8 { - return h[1] -} - -func (h header) Flags() uint16 { - return binary.BigEndian.Uint16(h[2:4]) -} - -func (h header) StreamID() uint32 { - return binary.BigEndian.Uint32(h[4:8]) -} - -func (h header) Length() uint32 { - return binary.BigEndian.Uint32(h[8:12]) -} - -func (h header) String() string { - return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d", - h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length()) -} - -func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) { - h[0] = protoVersion - h[1] = msgType - binary.BigEndian.PutUint16(h[2:4], flags) - binary.BigEndian.PutUint32(h[4:8], streamID) - binary.BigEndian.PutUint32(h[8:12], length) -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/const_test.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/const_test.go deleted file mode 100644 index 153da18b9..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/const_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package yamux - -import ( - "testing" -) - -func TestConst(t *testing.T) { - if protoVersion != 0 { - t.Fatalf("bad: %v", protoVersion) - } - - if typeData != 0 { - t.Fatalf("bad: %v", typeData) - } - if typeWindowUpdate != 1 { - t.Fatalf("bad: %v", typeWindowUpdate) - } - if typePing != 2 { - t.Fatalf("bad: %v", typePing) - } - if typeGoAway != 3 { - t.Fatalf("bad: %v", typeGoAway) - } - - if flagSYN != 1 { - t.Fatalf("bad: %v", flagSYN) - } - if flagACK != 2 { - t.Fatalf("bad: %v", flagACK) - } - if flagFIN != 4 { - t.Fatalf("bad: %v", flagFIN) - } - if flagRST != 8 { - t.Fatalf("bad: %v", flagRST) - } - - if goAwayNormal != 0 { - t.Fatalf("bad: %v", goAwayNormal) - } - if goAwayProtoErr != 1 { - t.Fatalf("bad: %v", goAwayProtoErr) - } - if goAwayInternalErr != 2 { - t.Fatalf("bad: %v", goAwayInternalErr) - } - - if headerSize != 12 { - t.Fatalf("bad header size") - } -} - -func TestEncodeDecode(t *testing.T) { - hdr := header(make([]byte, headerSize)) - hdr.encode(typeWindowUpdate, flagACK|flagRST, 1234, 4321) - - if hdr.Version() != protoVersion { - t.Fatalf("bad: %v", hdr) - } - if hdr.MsgType() != typeWindowUpdate { - t.Fatalf("bad: %v", hdr) - } - if hdr.Flags() != flagACK|flagRST { - t.Fatalf("bad: %v", hdr) - } - if hdr.StreamID() != 1234 { - t.Fatalf("bad: %v", hdr) - } - if hdr.Length() != 4321 { - t.Fatalf("bad: %v", hdr) - } -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/mux.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/mux.go deleted file mode 100644 index daec1d194..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/mux.go +++ /dev/null @@ -1,80 +0,0 @@ -package yamux - -import ( - "fmt" - "io" - "os" - "time" -) - -// Config is used to tune the Yamux session -type Config struct { - // AcceptBacklog is used to limit how many streams may be - // waiting an accept. - AcceptBacklog int - - // EnableKeepalive is used to do a period keep alive - // messages using a ping. - EnableKeepAlive bool - - // KeepAliveInterval is how often to perform the keep alive - KeepAliveInterval time.Duration - - // MaxStreamWindowSize is used to control the maximum - // window size that we allow for a stream. - MaxStreamWindowSize uint32 - - // LogOutput is used to control the log destination - LogOutput io.Writer -} - -// DefaultConfig is used to return a default configuration -func DefaultConfig() *Config { - return &Config{ - AcceptBacklog: 256, - EnableKeepAlive: true, - KeepAliveInterval: 30 * time.Second, - MaxStreamWindowSize: initialStreamWindow, - LogOutput: os.Stderr, - } -} - -// VerifyConfig is used to verify the sanity of configuration -func VerifyConfig(config *Config) error { - if config.AcceptBacklog <= 0 { - return fmt.Errorf("backlog must be positive") - } - if config.KeepAliveInterval == 0 { - return fmt.Errorf("keep-alive interval must be positive") - } - if config.MaxStreamWindowSize < initialStreamWindow { - return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow) - } - return nil -} - -// Server is used to initialize a new server-side connection. -// There must be at most one server-side connection. If a nil config is -// provided, the DefaultConfiguration will be used. -func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) { - if config == nil { - config = DefaultConfig() - } - if err := VerifyConfig(config); err != nil { - return nil, err - } - return newSession(config, conn, false), nil -} - -// Client is used to initialize a new client-side connection. -// There must be at most one client-side connection. -func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) { - if config == nil { - config = DefaultConfig() - } - - if err := VerifyConfig(config); err != nil { - return nil, err - } - return newSession(config, conn, true), nil -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/session.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/session.go deleted file mode 100644 index 2def31e3c..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/session.go +++ /dev/null @@ -1,505 +0,0 @@ -package yamux - -import ( - "bufio" - "fmt" - "io" - "io/ioutil" - "log" - "math" - "net" - "strings" - "sync" - "sync/atomic" - "time" -) - -// Session is used to wrap a reliable ordered connection and to -// multiplex it into multiple streams. -type Session struct { - // remoteGoAway indicates the remote side does - // not want futher connections. Must be first for alignment. - remoteGoAway int32 - - // localGoAway indicates that we should stop - // accepting futher connections. Must be first for alignment. - localGoAway int32 - - // nextStreamID is the next stream we should - // send. This depends if we are a client/server. - nextStreamID uint32 - - // config holds our configuration - config *Config - - // logger is used for our logs - logger *log.Logger - - // conn is the underlying connection - conn io.ReadWriteCloser - - // bufRead is a buffered reader - bufRead *bufio.Reader - - // pings is used to track inflight pings - pings map[uint32]chan struct{} - pingID uint32 - pingLock sync.Mutex - - // streams maps a stream id to a stream - streams map[uint32]*Stream - streamLock sync.Mutex - - // acceptCh is used to pass ready streams to the client - acceptCh chan *Stream - - // sendCh is used to mark a stream as ready to send, - // or to send a header out directly. - sendCh chan sendReady - - // shutdown is used to safely close a session - shutdown bool - shutdownErr error - shutdownCh chan struct{} - shutdownLock sync.Mutex -} - -// sendReady is used to either mark a stream as ready -// or to directly send a header -type sendReady struct { - Hdr []byte - Body io.Reader - Err chan error -} - -// newSession is used to construct a new session -func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { - s := &Session{ - config: config, - logger: log.New(config.LogOutput, "", log.LstdFlags), - conn: conn, - bufRead: bufio.NewReader(conn), - pings: make(map[uint32]chan struct{}), - streams: make(map[uint32]*Stream), - acceptCh: make(chan *Stream, config.AcceptBacklog), - sendCh: make(chan sendReady, 64), - shutdownCh: make(chan struct{}), - } - if client { - s.nextStreamID = 1 - } else { - s.nextStreamID = 2 - } - go s.recv() - go s.send() - if config.EnableKeepAlive { - go s.keepalive() - } - return s -} - -// IsClosed does a safe check to see if we have shutdown -func (s *Session) IsClosed() bool { - select { - case <-s.shutdownCh: - return true - default: - return false - } -} - -// Open is used to create a new stream as a net.Conn -func (s *Session) Open() (net.Conn, error) { - return s.OpenStream() -} - -// OpenStream is used to create a new stream -func (s *Session) OpenStream() (*Stream, error) { - if s.IsClosed() { - return nil, ErrSessionShutdown - } - if atomic.LoadInt32(&s.remoteGoAway) == 1 { - return nil, ErrRemoteGoAway - } - -GET_ID: - // Get and ID, and check for stream exhaustion - id := atomic.LoadUint32(&s.nextStreamID) - if id >= math.MaxUint32-1 { - return nil, ErrStreamsExhausted - } - if !atomic.CompareAndSwapUint32(&s.nextStreamID, id, id+2) { - goto GET_ID - } - - // Register the stream - stream := newStream(s, id, streamInit) - s.streamLock.Lock() - s.streams[id] = stream - s.streamLock.Unlock() - - // Send the window update to create - return stream, stream.sendWindowUpdate() -} - -// Accept is used to block until the next available stream -// is ready to be accepted. -func (s *Session) Accept() (net.Conn, error) { - return s.AcceptStream() -} - -// AcceptStream is used to block until the next available stream -// is ready to be accepted. -func (s *Session) AcceptStream() (*Stream, error) { - select { - case stream := <-s.acceptCh: - return stream, stream.sendWindowUpdate() - case <-s.shutdownCh: - return nil, s.shutdownErr - } -} - -// Close is used to close the session and all streams. -// Attempts to send a GoAway before closing the connection. -func (s *Session) Close() error { - s.shutdownLock.Lock() - defer s.shutdownLock.Unlock() - - if s.shutdown { - return nil - } - s.shutdown = true - if s.shutdownErr == nil { - s.shutdownErr = ErrSessionShutdown - } - close(s.shutdownCh) - s.conn.Close() - - s.streamLock.Lock() - defer s.streamLock.Unlock() - for _, stream := range s.streams { - stream.forceClose() - } - return nil -} - -// exitErr is used to handle an error that is causing the -// session to terminate. -func (s *Session) exitErr(err error) { - s.shutdownLock.Lock() - if s.shutdownErr == nil { - s.shutdownErr = err - } - s.shutdownLock.Unlock() - s.Close() -} - -// GoAway can be used to prevent accepting further -// connections. It does not close the underlying conn. -func (s *Session) GoAway() error { - return s.waitForSend(s.goAway(goAwayNormal), nil) -} - -// goAway is used to send a goAway message -func (s *Session) goAway(reason uint32) header { - atomic.SwapInt32(&s.localGoAway, 1) - hdr := header(make([]byte, headerSize)) - hdr.encode(typeGoAway, 0, 0, reason) - return hdr -} - -// Ping is used to measure the RTT response time -func (s *Session) Ping() (time.Duration, error) { - // Get a channel for the ping - ch := make(chan struct{}) - - // Get a new ping id, mark as pending - s.pingLock.Lock() - id := s.pingID - s.pingID++ - s.pings[id] = ch - s.pingLock.Unlock() - - // Send the ping request - hdr := header(make([]byte, headerSize)) - hdr.encode(typePing, flagSYN, 0, id) - if err := s.waitForSend(hdr, nil); err != nil { - return 0, err - } - - // Wait for a response - start := time.Now() - select { - case <-ch: - case <-s.shutdownCh: - return 0, ErrSessionShutdown - } - - // Compute the RTT - return time.Now().Sub(start), nil -} - -// keepalive is a long running goroutine that periodically does -// a ping to keep the connection alive. -func (s *Session) keepalive() { - for { - select { - case <-time.After(s.config.KeepAliveInterval): - s.Ping() - case <-s.shutdownCh: - return - } - } -} - -// waitForSendErr waits to send a header, checking for a potential shutdown -func (s *Session) waitForSend(hdr header, body io.Reader) error { - errCh := make(chan error, 1) - return s.waitForSendErr(hdr, body, errCh) -} - -// waitForSendErr waits to send a header, checking for a potential shutdown -func (s *Session) waitForSendErr(hdr header, body io.Reader, errCh chan error) error { - ready := sendReady{Hdr: hdr, Body: body, Err: errCh} - select { - case s.sendCh <- ready: - case <-s.shutdownCh: - return ErrSessionShutdown - } - select { - case err := <-errCh: - return err - case <-s.shutdownCh: - return ErrSessionShutdown - } -} - -// sendNoWait does a send without waiting -func (s *Session) sendNoWait(hdr header) error { - select { - case s.sendCh <- sendReady{Hdr: hdr}: - return nil - case <-s.shutdownCh: - return ErrSessionShutdown - } -} - -// send is a long running goroutine that sends data -func (s *Session) send() { - for { - select { - case ready := <-s.sendCh: - // Send a header if ready - if ready.Hdr != nil { - sent := 0 - for sent < len(ready.Hdr) { - n, err := s.conn.Write(ready.Hdr[sent:]) - if err != nil { - s.logger.Printf("[ERR] yamux: Failed to write header: %v", err) - asyncSendErr(ready.Err, err) - s.exitErr(err) - return - } - sent += n - } - } - - // Send data from a body if given - if ready.Body != nil { - _, err := io.Copy(s.conn, ready.Body) - if err != nil { - s.logger.Printf("[ERR] yamux: Failed to write body: %v", err) - asyncSendErr(ready.Err, err) - s.exitErr(err) - return - } - } - - // No error, successful send - asyncSendErr(ready.Err, nil) - case <-s.shutdownCh: - return - } - } -} - -// recv is a long running goroutine that accepts new data -func (s *Session) recv() { - hdr := header(make([]byte, headerSize)) - var handler func(header) error - for { - // Read the header - if _, err := io.ReadFull(s.bufRead, hdr); err != nil { - if err != io.EOF && !strings.Contains(err.Error(), "closed") && !strings.Contains(err.Error(), "reset by peer") { - s.logger.Printf("[ERR] yamux: Failed to read header: %v", err) - } - s.exitErr(err) - return - } - - // Verify the version - if hdr.Version() != protoVersion { - s.logger.Printf("[ERR] yamux: Invalid protocol version: %d", hdr.Version()) - s.exitErr(ErrInvalidVersion) - return - } - - // Switch on the type - switch hdr.MsgType() { - case typeData: - handler = s.handleStreamMessage - case typeWindowUpdate: - handler = s.handleStreamMessage - case typeGoAway: - handler = s.handleGoAway - case typePing: - handler = s.handlePing - default: - s.exitErr(ErrInvalidMsgType) - return - } - - // Invoke the handler - if err := handler(hdr); err != nil { - s.exitErr(err) - return - } - } -} - -// handleStreamMessage handles either a data or window update frame -func (s *Session) handleStreamMessage(hdr header) error { - // Check for a new stream creation - id := hdr.StreamID() - flags := hdr.Flags() - if flags&flagSYN == flagSYN { - if err := s.incomingStream(id); err != nil { - return err - } - } - - // Get the stream - s.streamLock.Lock() - stream := s.streams[id] - s.streamLock.Unlock() - - // If we do not have a stream, likely we sent a RST - if stream == nil { - // Drain any data on the wire - if hdr.MsgType() == typeData && hdr.Length() > 0 { - s.logger.Printf("[WARN] yamux: Discarding data for stream: %d", id) - if _, err := io.CopyN(ioutil.Discard, s.bufRead, int64(hdr.Length())); err != nil { - s.logger.Printf("[ERR] yamux: Failed to discard data: %v", err) - return nil - } - } else { - s.logger.Printf("[WARN] yamux: frame for missing stream: %v", hdr) - } - return nil - } - - // Check if this is a window update - if hdr.MsgType() == typeWindowUpdate { - if err := stream.incrSendWindow(hdr, flags); err != nil { - s.sendNoWait(s.goAway(goAwayProtoErr)) - return err - } - return nil - } - - // Read the new data - if err := stream.readData(hdr, flags, s.bufRead); err != nil { - s.sendNoWait(s.goAway(goAwayProtoErr)) - return err - } - return nil -} - -// handlePing is invokde for a typePing frame -func (s *Session) handlePing(hdr header) error { - flags := hdr.Flags() - pingID := hdr.Length() - - // Check if this is a query, respond back - if flags&flagSYN == flagSYN { - hdr := header(make([]byte, headerSize)) - hdr.encode(typePing, flagACK, 0, pingID) - s.sendNoWait(hdr) - return nil - } - - // Handle a response - s.pingLock.Lock() - ch := s.pings[pingID] - if ch != nil { - delete(s.pings, pingID) - close(ch) - } - s.pingLock.Unlock() - return nil -} - -// handleGoAway is invokde for a typeGoAway frame -func (s *Session) handleGoAway(hdr header) error { - code := hdr.Length() - switch code { - case goAwayNormal: - atomic.SwapInt32(&s.remoteGoAway, 1) - case goAwayProtoErr: - s.logger.Printf("[ERR] yamux: received protocol error go away") - return fmt.Errorf("yamux protocol error") - case goAwayInternalErr: - s.logger.Printf("[ERR] yamux: received internal error go away") - return fmt.Errorf("remote yamux internal error") - default: - s.logger.Printf("[ERR] yamux: received unexpected go away") - return fmt.Errorf("unexpected go away received") - } - return nil -} - -// incomingStream is used to create a new incoming stream -func (s *Session) incomingStream(id uint32) error { - // Reject immediately if we are doing a go away - if atomic.LoadInt32(&s.localGoAway) == 1 { - hdr := header(make([]byte, headerSize)) - hdr.encode(typeWindowUpdate, flagRST, id, 0) - return s.sendNoWait(hdr) - } - - // Allocate a new stream - stream := newStream(s, id, streamSYNReceived) - - s.streamLock.Lock() - defer s.streamLock.Unlock() - - // Check if stream already exists - if _, ok := s.streams[id]; ok { - s.logger.Printf("[ERR] yamux: duplicate stream declared") - s.sendNoWait(s.goAway(goAwayProtoErr)) - return ErrDuplicateStream - } - - // Register the stream - s.streams[id] = stream - - // Check if we've exceeded the backlog - select { - case s.acceptCh <- stream: - return nil - default: - // Backlog exceeded! RST the stream - s.logger.Printf("[WARN] yamux: backlog exceeded, forcing connection reset") - delete(s.streams, id) - stream.sendHdr.encode(typeWindowUpdate, flagRST, id, 0) - return s.sendNoWait(stream.sendHdr) - } -} - -// closeStream is used to close a stream once both sides have -// issued a close. -func (s *Session) closeStream(id uint32) { - s.streamLock.Lock() - delete(s.streams, id) - s.streamLock.Unlock() -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/session_test.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/session_test.go deleted file mode 100644 index 245269f74..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/session_test.go +++ /dev/null @@ -1,729 +0,0 @@ -package yamux - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "runtime" - "sync" - "testing" - "time" -) - -type pipeConn struct { - reader *io.PipeReader - writer *io.PipeWriter -} - -func (p *pipeConn) Read(b []byte) (int, error) { - return p.reader.Read(b) -} - -func (p *pipeConn) Write(b []byte) (int, error) { - return p.writer.Write(b) -} - -func (p *pipeConn) Close() error { - p.reader.Close() - return p.writer.Close() -} - -func testConn() (io.ReadWriteCloser, io.ReadWriteCloser) { - read1, write1 := io.Pipe() - read2, write2 := io.Pipe() - return &pipeConn{read1, write2}, &pipeConn{read2, write1} -} - -func testClientServer() (*Session, *Session) { - conf := DefaultConfig() - conf.AcceptBacklog = 64 - conf.KeepAliveInterval = 100 * time.Millisecond - return testClientServerConfig(conf) -} - -func testClientServerConfig(conf *Config) (*Session, *Session) { - conn1, conn2 := testConn() - client, _ := Client(conn1, conf) - server, _ := Server(conn2, conf) - return client, server -} - -func TestPing(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - rtt, err := client.Ping() - if err != nil { - t.Fatalf("err: %v", err) - } - if rtt == 0 { - t.Fatalf("bad: %v", rtt) - } - - rtt, err = server.Ping() - if err != nil { - t.Fatalf("err: %v", err) - } - if rtt == 0 { - t.Fatalf("bad: %v", rtt) - } -} - -func TestAccept(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - wg := &sync.WaitGroup{} - wg.Add(4) - - go func() { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - if id := stream.StreamID(); id != 1 { - t.Fatalf("bad: %v", id) - } - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - go func() { - defer wg.Done() - stream, err := client.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - if id := stream.StreamID(); id != 2 { - t.Fatalf("bad: %v", id) - } - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - go func() { - defer wg.Done() - stream, err := server.OpenStream() - if err != nil { - t.Fatalf("err: %v", err) - } - if id := stream.StreamID(); id != 2 { - t.Fatalf("bad: %v", id) - } - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - go func() { - defer wg.Done() - stream, err := client.OpenStream() - if err != nil { - t.Fatalf("err: %v", err) - } - if id := stream.StreamID(); id != 1 { - t.Fatalf("bad: %v", id) - } - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - doneCh := make(chan struct{}) - go func() { - wg.Wait() - close(doneCh) - }() - - select { - case <-doneCh: - case <-time.After(time.Second): - panic("timeout") - } -} - -func TestSendData_Small(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - wg := &sync.WaitGroup{} - wg.Add(2) - - go func() { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - - buf := make([]byte, 4) - for i := 0; i < 1000; i++ { - n, err := stream.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("short read: %d", n) - } - if string(buf) != "test" { - t.Fatalf("bad: %s", buf) - } - } - - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - go func() { - defer wg.Done() - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - - for i := 0; i < 1000; i++ { - n, err := stream.Write([]byte("test")) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("short write %d", n) - } - } - - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - doneCh := make(chan struct{}) - go func() { - wg.Wait() - close(doneCh) - }() - select { - case <-doneCh: - case <-time.After(time.Second): - panic("timeout") - } -} - -func TestSendData_Large(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - data := make([]byte, 512*1024) - for idx := range data { - data[idx] = byte(idx % 256) - } - - wg := &sync.WaitGroup{} - wg.Add(2) - - go func() { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - - buf := make([]byte, 4*1024) - for i := 0; i < 128; i++ { - n, err := stream.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4*1024 { - t.Fatalf("short read: %d", n) - } - for idx := range buf { - if buf[idx] != byte(idx%256) { - t.Fatalf("bad: %v %v %v", i, idx, buf[idx]) - } - } - } - - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - go func() { - defer wg.Done() - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - - n, err := stream.Write(data) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != len(data) { - t.Fatalf("short write %d", n) - } - - if err := stream.Close(); err != nil { - t.Fatalf("err: %v", err) - } - }() - - doneCh := make(chan struct{}) - go func() { - wg.Wait() - close(doneCh) - }() - select { - case <-doneCh: - case <-time.After(time.Second): - panic("timeout") - } -} - -func TestGoAway(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - if err := server.GoAway(); err != nil { - t.Fatalf("err: %v", err) - } - - _, err := client.Open() - if err != ErrRemoteGoAway { - t.Fatalf("err: %v", err) - } -} - -func TestManyStreams(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - wg := &sync.WaitGroup{} - - acceptor := func(i int) { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - buf := make([]byte, 512) - for { - n, err := stream.Read(buf) - if err == io.EOF { - return - } - if err != nil { - t.Fatalf("err: %v", err) - } - if n == 0 { - t.Fatalf("err: %v", err) - } - } - } - sender := func(i int) { - defer wg.Done() - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - msg := fmt.Sprintf("%08d", i) - for i := 0; i < 1000; i++ { - n, err := stream.Write([]byte(msg)) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != len(msg) { - t.Fatalf("short write %d", n) - } - } - } - - for i := 0; i < 50; i++ { - wg.Add(2) - go acceptor(i) - go sender(i) - } - - wg.Wait() -} - -func TestManyStreams_PingPong(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - wg := &sync.WaitGroup{} - - ping := []byte("ping") - pong := []byte("pong") - - acceptor := func(i int) { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - buf := make([]byte, 4) - for { - n, err := stream.Read(buf) - if err == io.EOF { - return - } - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("err: %v", err) - } - if !bytes.Equal(buf, ping) { - t.Fatalf("bad: %s", buf) - } - n, err = stream.Write(pong) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("err: %v", err) - } - } - } - sender := func(i int) { - defer wg.Done() - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - buf := make([]byte, 4) - for i := 0; i < 1000; i++ { - n, err := stream.Write(ping) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("short write %d", n) - } - - n, err = stream.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 4 { - t.Fatalf("err: %v", err) - } - if !bytes.Equal(buf, pong) { - t.Fatalf("bad: %s", buf) - } - } - } - - for i := 0; i < 50; i++ { - wg.Add(2) - go acceptor(i) - go sender(i) - } - - wg.Wait() -} - -func TestHalfClose(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - if _, err := stream.Write([]byte("a")); err != nil { - t.Fatalf("err: %v", err) - } - - stream2, err := server.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - stream2.Close() // Half close - - buf := make([]byte, 4) - n, err := stream2.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 1 { - t.Fatalf("bad: %v", n) - } - - // Send more - if _, err := stream.Write([]byte("bcd")); err != nil { - t.Fatalf("err: %v", err) - } - stream.Close() - - // Read after close - n, err = stream2.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != 3 { - t.Fatalf("bad: %v", n) - } - - // EOF after close - n, err = stream2.Read(buf) - if err != io.EOF { - t.Fatalf("err: %v", err) - } - if n != 0 { - t.Fatalf("bad: %v", n) - } -} - -func TestReadDeadline(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - stream2, err := server.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream2.Close() - - if err := stream.SetReadDeadline(time.Now().Add(5 * time.Millisecond)); err != nil { - t.Fatalf("err: %v", err) - } - - buf := make([]byte, 4) - if _, err := stream.Read(buf); err != ErrTimeout { - t.Fatalf("err: %v", err) - } -} - -func TestWriteDeadline(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - stream2, err := server.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream2.Close() - - if err := stream.SetWriteDeadline(time.Now().Add(50 * time.Millisecond)); err != nil { - t.Fatalf("err: %v", err) - } - - buf := make([]byte, 512) - for i := 0; i < int(initialStreamWindow); i++ { - _, err := stream.Write(buf) - if err != nil && err == ErrTimeout { - return - } else if err != nil { - t.Fatalf("err: %v", err) - } - } - t.Fatalf("Expected timeout") -} - -func TestBacklogExceeded(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - // Fill the backlog - max := client.config.AcceptBacklog - for i := 0; i < max; i++ { - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - if _, err := stream.Write([]byte("foo")); err != nil { - t.Fatalf("err: %v", err) - } - } - - // Exceed the backlog! - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - if _, err := stream.Write([]byte("foo")); err != nil { - t.Fatalf("err: %v", err) - } - - buf := make([]byte, 4) - stream.SetReadDeadline(time.Now().Add(50 * time.Millisecond)) - if _, err := stream.Read(buf); err != ErrConnectionReset { - t.Fatalf("err: %v", err) - } -} - -func TestKeepAlive(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - time.Sleep(200 * time.Millisecond) - - // Ping value should increase - client.pingLock.Lock() - defer client.pingLock.Unlock() - if client.pingID == 0 { - t.Fatalf("should ping") - } - - server.pingLock.Lock() - defer server.pingLock.Unlock() - if server.pingID == 0 { - t.Fatalf("should ping") - } -} - -func TestLargeWindow(t *testing.T) { - conf := DefaultConfig() - conf.MaxStreamWindowSize *= 2 - - client, server := testClientServerConfig(conf) - defer client.Close() - defer server.Close() - - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - stream2, err := server.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream2.Close() - - stream.SetWriteDeadline(time.Now().Add(10 * time.Millisecond)) - buf := make([]byte, conf.MaxStreamWindowSize) - n, err := stream.Write(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if n != len(buf) { - t.Fatalf("short write: %d", n) - } -} - -type UnlimitedReader struct{} - -func (u *UnlimitedReader) Read(p []byte) (int, error) { - runtime.Gosched() - return len(p), nil -} - -func TestSendData_VeryLarge(t *testing.T) { - client, server := testClientServer() - defer client.Close() - defer server.Close() - - var n int64 = 1 * 1024 * 1024 * 1024 - var workers int = 16 - - wg := &sync.WaitGroup{} - wg.Add(workers * 2) - - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - stream, err := server.AcceptStream() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - buf := make([]byte, 4) - _, err = stream.Read(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - if !bytes.Equal(buf, []byte{0, 1, 2, 3}) { - t.Fatalf("bad header") - } - - recv, err := io.Copy(ioutil.Discard, stream) - if err != nil { - t.Fatalf("err: %v", err) - } - if recv != n { - t.Fatalf("bad: %v", recv) - } - }() - } - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - stream, err := client.Open() - if err != nil { - t.Fatalf("err: %v", err) - } - defer stream.Close() - - _, err = stream.Write([]byte{0, 1, 2, 3}) - if err != nil { - t.Fatalf("err: %v", err) - } - - unlimited := &UnlimitedReader{} - sent, err := io.Copy(stream, io.LimitReader(unlimited, n)) - if err != nil { - t.Fatalf("err: %v", err) - } - if sent != n { - t.Fatalf("bad: %v", sent) - } - }() - } - - doneCh := make(chan struct{}) - go func() { - wg.Wait() - close(doneCh) - }() - select { - case <-doneCh: - case <-time.After(20 * time.Second): - panic("timeout") - } -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/spec.md b/Godeps/_workspace/src/github.com/hashicorp/yamux/spec.md deleted file mode 100644 index 419470b7f..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/spec.md +++ /dev/null @@ -1,141 +0,0 @@ -# Specification - -We use this document to detail the internal specification of Yamux. -This is used both as a guide for implementing Yamux, but also for -alternative interoperable libraries to be built. - -# Framing - -Yamux uses a streaming connection underneath, but imposes a message -framing so that it can be shared between many logical streams. Each -frame contains a header like: - -* Version (8 bits) -* Type (8 bits) -* Flags (16 bits) -* StreamID (32 bits) -* Length (32 bits) - -This means that each header has a 12 byte overhead. -All fields are encoded in network order (big endian). -Each field is described below: - -## Version Field - -The version field is used for future backwards compatibily. At the -current time, the field is always set to 0, to indicate the initial -version. - -## Type Field - -The type field is used to switch the frame message type. The following -message types are supported: - -* 0x0 Data - Used to transmit data. May transmit zero length payloads - depending on the flags. - -* 0x1 Window Update - Used to updated the senders receive window size. - This is used to implement per-session flow control. - -* 0x2 Ping - Used to measure RTT. It can also be used to heart-beat - and do keep-alives over TCP. - -* 0x3 Go Away - Used to close a session. - -## Flag Field - -The flags field is used to provide additional information related -to the message type. The following flags are supported: - -* 0x1 SYN - Signals the start of a new stream. May be sent with a data or - window update message. Also sent with a ping to indicate outbound. - -* 0x2 ACK - Acknowledges the start of a new stream. May be sent with a data - or window update message. Also sent with a ping to indicate response. - -* 0x4 FIN - Performs a half-close of a stream. May be sent with a data - message or window update. - -* 0x8 RST - Reset a stream immediately. May be sent with a data or - window update message. - -## StreamID Field - -The StreamID field is used to identify the logical stream the frame -is addressing. The client side should use odd ID's, and the server even. -This prevents any collisions. Additionally, the 0 ID is reserved to represent -the session. - -Both Ping and Go Away messages should always use the 0 StreamID. - -## Length Field - -The meaning of the length field depends on the message type: - -* Data - provides the length of bytes following the header -* Window update - provides a delta update to the window size -* Ping - Contains an opaque value, echoed back -* Go Away - Contains an error code - -# Message Flow - -There is no explicit connection setup, as Yamux relies on an underlying -transport to be provided. However, there is a distinction between client -and server side of the connection. - -## Opening a stream - -To open a stream, an initial data or window update frame is sent -with a new StreamID. The SYN flag should be set to signal a new stream. - -The receiver must then reply with either a data or window update frame -with the StreamID along with the ACK flag to accept the stream or with -the RST flag to reject the stream. - -Because we are relying on the reliable stream underneath, a connection -can begin sending data once the SYN flag is sent. The corresponding -ACK does not need to be received. This is particularly well suited -for an RPC system where a client wants to open a stream and immediately -fire a request without wiating for the RTT of the ACK. - -This does introduce the possibility of a connection being rejected -after data has been sent already. This is a slight semantic difference -from TCP, where the conection cannot be refused after it is opened. -Clients should be prepared to handle this by checking for an error -that indicates a RST was received. - -## Closing a stream - -To close a stream, either side sends a data or window update frame -along with the FIN flag. This does a half-close indicating the sender -will send no further data. - -Once both sides have closed the connection, the stream is closed. - -Alternatively, if an error occurs, the RST flag can be used to -hard close a stream immediately. - -## Flow Control - -When Yamux is initially starts each stream with a 256KB window size. -There is no window size for the session. - -To prevent the streams from stalling, window update frames should be -sent regularly. Yamux can be configured to provide a larger limit for -windows sizes. Both sides assume the initial 256KB window, but can -immediately send a window update as part of the SYN/ACK indicating a -larger window. - -Both sides should track the number of bytes sent in Data frames -only, as only they are tracked as part of the window size. - -## Session termination - -When a session is being terminated, the Go Away message should -be sent. The Length should be set to one of the following to -provide an error code: - -* 0x0 Normal termination -* 0x1 Protocol error -* 0x2 Internal error - diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/stream.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/stream.go deleted file mode 100644 index b842dad21..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/stream.go +++ /dev/null @@ -1,417 +0,0 @@ -package yamux - -import ( - "bytes" - "io" - "sync" - "sync/atomic" - "time" -) - -type streamState int - -const ( - streamInit streamState = iota - streamSYNSent - streamSYNReceived - streamEstablished - streamLocalClose - streamRemoteClose - streamClosed - streamReset -) - -// Stream is used to represent a logical stream -// within a session. -type Stream struct { - recvWindow uint32 - sendWindow uint32 - - id uint32 - session *Session - - state streamState - stateLock sync.Mutex - - recvBuf bytes.Buffer - recvLock sync.Mutex - - controlHdr header - controlErr chan error - controlHdrLock sync.Mutex - - sendHdr header - sendErr chan error - sendLock sync.Mutex - - recvNotifyCh chan struct{} - sendNotifyCh chan struct{} - - readDeadline time.Time - writeDeadline time.Time -} - -// newStream is used to construct a new stream within -// a given session for an ID -func newStream(session *Session, id uint32, state streamState) *Stream { - s := &Stream{ - id: id, - session: session, - state: state, - controlHdr: header(make([]byte, headerSize)), - controlErr: make(chan error, 1), - sendHdr: header(make([]byte, headerSize)), - sendErr: make(chan error, 1), - recvWindow: initialStreamWindow, - sendWindow: initialStreamWindow, - recvNotifyCh: make(chan struct{}, 1), - sendNotifyCh: make(chan struct{}, 1), - } - return s -} - -// Session returns the associated stream session -func (s *Stream) Session() *Session { - return s.session -} - -// StreamID returns the ID of this stream -func (s *Stream) StreamID() uint32 { - return s.id -} - -// Read is used to read from the stream -func (s *Stream) Read(b []byte) (n int, err error) { - defer asyncNotify(s.recvNotifyCh) -START: - s.stateLock.Lock() - switch s.state { - case streamRemoteClose: - fallthrough - case streamClosed: - if s.recvBuf.Len() == 0 { - s.stateLock.Unlock() - return 0, io.EOF - } - case streamReset: - s.stateLock.Unlock() - return 0, ErrConnectionReset - } - s.stateLock.Unlock() - - // If there is no data available, block - s.recvLock.Lock() - if s.recvBuf.Len() == 0 { - s.recvLock.Unlock() - goto WAIT - } - - // Read any bytes - n, _ = s.recvBuf.Read(b) - s.recvLock.Unlock() - - // Send a window update potentially - err = s.sendWindowUpdate() - return n, err - -WAIT: - var timeout <-chan time.Time - if !s.readDeadline.IsZero() { - delay := s.readDeadline.Sub(time.Now()) - timeout = time.After(delay) - } - select { - case <-s.recvNotifyCh: - goto START - case <-timeout: - return 0, ErrTimeout - } -} - -// Write is used to write to the stream -func (s *Stream) Write(b []byte) (n int, err error) { - s.sendLock.Lock() - defer s.sendLock.Unlock() - total := 0 - for total < len(b) { - n, err := s.write(b[total:]) - total += n - if err != nil { - return total, err - } - } - return total, nil -} - -// write is used to write to the stream, may return on -// a short write. -func (s *Stream) write(b []byte) (n int, err error) { - var flags uint16 - var max uint32 - var body io.Reader -START: - s.stateLock.Lock() - switch s.state { - case streamLocalClose: - fallthrough - case streamClosed: - s.stateLock.Unlock() - return 0, ErrStreamClosed - case streamReset: - s.stateLock.Unlock() - return 0, ErrConnectionReset - } - s.stateLock.Unlock() - - // If there is no data available, block - window := atomic.LoadUint32(&s.sendWindow) - if window == 0 { - goto WAIT - } - - // Determine the flags if any - flags = s.sendFlags() - - // Send up to our send window - max = min(window, uint32(len(b))) - body = bytes.NewReader(b[:max]) - - // Send the header - s.sendHdr.encode(typeData, flags, s.id, max) - if err := s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil { - return 0, err - } - - // Reduce our send window - atomic.AddUint32(&s.sendWindow, ^uint32(max-1)) - - // Unlock - return int(max), err - -WAIT: - var timeout <-chan time.Time - if !s.writeDeadline.IsZero() { - delay := s.writeDeadline.Sub(time.Now()) - timeout = time.After(delay) - } - select { - case <-s.sendNotifyCh: - goto START - case <-timeout: - return 0, ErrTimeout - } - return 0, nil -} - -// sendFlags determines any flags that are appropriate -// based on the current stream state -func (s *Stream) sendFlags() uint16 { - s.stateLock.Lock() - defer s.stateLock.Unlock() - var flags uint16 - switch s.state { - case streamInit: - flags |= flagSYN - s.state = streamSYNSent - case streamSYNReceived: - flags |= flagACK - s.state = streamEstablished - } - return flags -} - -// sendWindowUpdate potentially sends a window update enabling -// further writes to take place. Must be invoked with the lock. -func (s *Stream) sendWindowUpdate() error { - s.controlHdrLock.Lock() - defer s.controlHdrLock.Unlock() - - // Determine the delta update - max := s.session.config.MaxStreamWindowSize - delta := max - atomic.LoadUint32(&s.recvWindow) - - // Determine the flags if any - flags := s.sendFlags() - - // Check if we can omit the update - if delta < (max/2) && flags == 0 { - return nil - } - - // Update our window - atomic.AddUint32(&s.recvWindow, delta) - - // Send the header - s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta) - if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { - return err - } - return nil -} - -// sendClose is used to send a FIN -func (s *Stream) sendClose() error { - s.controlHdrLock.Lock() - defer s.controlHdrLock.Unlock() - - flags := s.sendFlags() - flags |= flagFIN - s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0) - if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { - return err - } - return nil -} - -// Close is used to close the stream -func (s *Stream) Close() error { - s.stateLock.Lock() - switch s.state { - // Opened means we need to signal a close - case streamSYNSent: - fallthrough - case streamSYNReceived: - fallthrough - case streamEstablished: - s.state = streamLocalClose - goto SEND_CLOSE - - case streamLocalClose: - case streamRemoteClose: - s.state = streamClosed - s.session.closeStream(s.id) - goto SEND_CLOSE - - case streamClosed: - case streamReset: - default: - panic("unhandled state") - } - s.stateLock.Unlock() - return nil -SEND_CLOSE: - s.stateLock.Unlock() - s.sendClose() - s.notifyWaiting() - return nil -} - -// forceClose is used for when the session is exiting -func (s *Stream) forceClose() { - s.stateLock.Lock() - s.state = streamClosed - s.stateLock.Unlock() - s.notifyWaiting() -} - -// processFlags is used to update the state of the stream -// based on set flags, if any. Lock must be held -func (s *Stream) processFlags(flags uint16) error { - s.stateLock.Lock() - defer s.stateLock.Unlock() - if flags&flagACK == flagACK { - if s.state == streamSYNSent { - s.state = streamEstablished - } - - } else if flags&flagFIN == flagFIN { - switch s.state { - case streamSYNSent: - fallthrough - case streamSYNReceived: - fallthrough - case streamEstablished: - s.state = streamRemoteClose - s.notifyWaiting() - case streamLocalClose: - s.state = streamClosed - s.session.closeStream(s.id) - s.notifyWaiting() - default: - s.session.logger.Printf("[ERR] yamux: unexpected FIN flag in state %d", s.state) - return ErrUnexpectedFlag - } - } else if flags&flagRST == flagRST { - s.state = streamReset - s.session.closeStream(s.id) - s.notifyWaiting() - } - return nil -} - -// notifyWaiting notifies all the waiting channels -func (s *Stream) notifyWaiting() { - asyncNotify(s.recvNotifyCh) - asyncNotify(s.sendNotifyCh) -} - -// incrSendWindow updates the size of our send window -func (s *Stream) incrSendWindow(hdr header, flags uint16) error { - if err := s.processFlags(flags); err != nil { - return err - } - - // Increase window, unblock a sender - atomic.AddUint32(&s.sendWindow, hdr.Length()) - asyncNotify(s.sendNotifyCh) - return nil -} - -// readData is used to handle a data frame -func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error { - if err := s.processFlags(flags); err != nil { - return err - } - - // Check that our recv window is not exceeded - length := hdr.Length() - if length == 0 { - return nil - } - if remain := atomic.LoadUint32(&s.recvWindow); length > remain { - s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, remain, length) - return ErrRecvWindowExceeded - } - - // Wrap in a limited reader - conn = &io.LimitedReader{R: conn, N: int64(length)} - - // Copy into buffer - s.recvLock.Lock() - if _, err := io.Copy(&s.recvBuf, conn); err != nil { - s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err) - s.recvLock.Unlock() - return err - } - - // Decrement the receive window - atomic.AddUint32(&s.recvWindow, ^uint32(length-1)) - s.recvLock.Unlock() - - // Unblock any readers - asyncNotify(s.recvNotifyCh) - return nil -} - -// SetDeadline sets the read and write deadlines -func (s *Stream) SetDeadline(t time.Time) error { - if err := s.SetReadDeadline(t); err != nil { - return err - } - if err := s.SetWriteDeadline(t); err != nil { - return err - } - return nil -} - -// SetReadDeadline sets the deadline for future Read calls. -func (s *Stream) SetReadDeadline(t time.Time) error { - s.readDeadline = t - return nil -} - -// SetWriteDeadline sets the deadline for future Write calls -func (s *Stream) SetWriteDeadline(t time.Time) error { - s.writeDeadline = t - return nil -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/util.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/util.go deleted file mode 100644 index 5fe45afcd..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/util.go +++ /dev/null @@ -1,28 +0,0 @@ -package yamux - -// asyncSendErr is used to try an async send of an error -func asyncSendErr(ch chan error, err error) { - if ch == nil { - return - } - select { - case ch <- err: - default: - } -} - -// asyncNotify is used to signal a waiting goroutine -func asyncNotify(ch chan struct{}) { - select { - case ch <- struct{}{}: - default: - } -} - -// min computes the minimum of two values -func min(a, b uint32) uint32 { - if a < b { - return a - } - return b -} diff --git a/Godeps/_workspace/src/github.com/hashicorp/yamux/util_test.go b/Godeps/_workspace/src/github.com/hashicorp/yamux/util_test.go deleted file mode 100644 index dd14623af..000000000 --- a/Godeps/_workspace/src/github.com/hashicorp/yamux/util_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package yamux - -import ( - "testing" -) - -func TestAsyncSendErr(t *testing.T) { - ch := make(chan error) - asyncSendErr(ch, ErrTimeout) - select { - case <-ch: - t.Fatalf("should not get") - default: - } - - ch = make(chan error, 1) - asyncSendErr(ch, ErrTimeout) - select { - case <-ch: - default: - t.Fatalf("should get") - } -} - -func TestAsyncNotify(t *testing.T) { - ch := make(chan struct{}) - asyncNotify(ch) - select { - case <-ch: - t.Fatalf("should not get") - default: - } - - ch = make(chan struct{}, 1) - asyncNotify(ch) - select { - case <-ch: - default: - t.Fatalf("should get") - } -} - -func TestMin(t *testing.T) { - if min(1, 2) != 1 { - t.Fatalf("bad") - } - if min(2, 1) != 1 { - t.Fatalf("bad") - } -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE b/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE deleted file mode 100644 index 252e3d639..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2013, John Beisley -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/README.md b/Godeps/_workspace/src/github.com/huin/goupnp/README.md deleted file mode 100644 index ea2c155a1..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/README.md +++ /dev/null @@ -1,14 +0,0 @@ -goupnp is a UPnP client library for Go - -Installation ------------- - -Run `go get -u github.com/huin/goupnp`. - -Regenerating dcps generated source code: ----------------------------------------- - -1. Install gotasks: `go get -u github.com/jingweno/gotask` -2. Change to the gotasks directory: `cd gotasks` -3. Download UPnP specification data (if not done already): `wget http://upnp.org/resources/upnpresources.zip` -4. Regenerate source code: `gotask specgen -s upnpresources.zip -o ../dcps` diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go deleted file mode 100644 index cfe3ebe81..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_httpu_serving/example_httpu_serving.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/httpu" -) - -func main() { - srv := httpu.Server{ - Addr: "239.255.255.250:1900", - Multicast: true, - Handler: httpu.HandlerFunc(func(r *http.Request) { - log.Printf("Got %s %s message from %v: %v", r.Method, r.URL.Path, r.RemoteAddr, r.Header) - }), - } - err := srv.ListenAndServe() - log.Printf("Serving failed with error: %v", err) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go b/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go deleted file mode 100644 index bb9737b08..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/cmd/example_internetgateway1/example_internetgateway1.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1" -) - -func main() { - clients, errors, err := internetgateway1.NewWANPPPConnection1Clients() - if err != nil { - log.Fatal(err) - } - - fmt.Printf("Got %d errors finding servers and %d successfully discovered.\n", - len(errors), len(clients)) - for i, e := range errors { - fmt.Printf("Error finding server #%d: %v\n", i+1, e) - } - - for _, c := range clients { - dev := &c.ServiceClient.RootDevice.Device - srv := c.ServiceClient.Service - fmt.Println(dev.FriendlyName, " :: ", srv.String()) - scpd, err := srv.RequestSCDP() - if err != nil { - fmt.Printf(" Error requesting service SCPD: %v\n", err) - } else { - fmt.Println(" Available actions:") - for _, action := range scpd.Actions { - fmt.Printf(" * %s\n", action.Name) - for _, arg := range action.Arguments { - var varDesc string - if stateVar := scpd.GetStateVariable(arg.RelatedStateVariable); stateVar != nil { - varDesc = fmt.Sprintf(" (%s)", stateVar.DataType.Name) - } - fmt.Printf(" * [%s] %s%s\n", arg.Direction, arg.Name, varDesc) - } - } - } - - if scpd == nil || scpd.GetAction("GetExternalIPAddress") != nil { - ip, err := c.GetExternalIPAddress() - fmt.Println("GetExternalIPAddress: ", ip, err) - } - - if scpd == nil || scpd.GetAction("GetStatusInfo") != nil { - status, lastErr, uptime, err := c.GetStatusInfo() - fmt.Println("GetStatusInfo: ", status, lastErr, uptime, err) - } - - if scpd == nil || scpd.GetAction("GetIdleDisconnectTime") != nil { - idleTime, err := c.GetIdleDisconnectTime() - fmt.Println("GetIdleDisconnectTime: ", idleTime, err) - } - - if scpd == nil || scpd.GetAction("AddPortMapping") != nil { - err := c.AddPortMapping("", 5000, "TCP", 5001, "192.168.1.2", true, "Test port mapping", 0) - fmt.Println("AddPortMapping: ", err) - } - if scpd == nil || scpd.GetAction("DeletePortMapping") != nil { - err := c.DeletePortMapping("", 5000, "TCP") - fmt.Println("DeletePortMapping: ", err) - } - } -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go deleted file mode 100644 index 73dbcab1e..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1/internetgateway1.go +++ /dev/null @@ -1,3957 +0,0 @@ -// Client for UPnP Device Control Protocol Internet Gateway Device v1. -// -// This DCP is documented in detail at: http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf -// -// Typically, use one of the New* functions to discover services on the local -// network. -package internetgateway1 - -// Generated file - do not edit by hand. See README.md - -import ( - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/soap" -) - -// Hack to avoid Go complaining if time isn't used. -var _ time.Time - -// Device URNs: -const ( - URN_LANDevice_1 = "urn:schemas-upnp-org:device:LANDevice:1" - URN_WANConnectionDevice_1 = "urn:schemas-upnp-org:device:WANConnectionDevice:1" - URN_WANDevice_1 = "urn:schemas-upnp-org:device:WANDevice:1" -) - -// Service URNs: -const ( - URN_LANHostConfigManagement_1 = "urn:schemas-upnp-org:service:LANHostConfigManagement:1" - URN_Layer3Forwarding_1 = "urn:schemas-upnp-org:service:Layer3Forwarding:1" - URN_WANCableLinkConfig_1 = "urn:schemas-upnp-org:service:WANCableLinkConfig:1" - URN_WANCommonInterfaceConfig_1 = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" - URN_WANDSLLinkConfig_1 = "urn:schemas-upnp-org:service:WANDSLLinkConfig:1" - URN_WANEthernetLinkConfig_1 = "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" - URN_WANIPConnection_1 = "urn:schemas-upnp-org:service:WANIPConnection:1" - URN_WANPOTSLinkConfig_1 = "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1" - URN_WANPPPConnection_1 = "urn:schemas-upnp-org:service:WANPPPConnection:1" -) - -// LANHostConfigManagement1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:LANHostConfigManagement:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type LANHostConfigManagement1 struct { - goupnp.ServiceClient -} - -// NewLANHostConfigManagement1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil { - return - } - clients = make([]*LANHostConfigManagement1, len(genericClients)) - for i := range genericClients { - clients[i] = &LANHostConfigManagement1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewDHCPServerConfigurable: -// -// -func (client *LANHostConfigManagement1) SetDHCPServerConfigurable(NewDHCPServerConfigurable bool) (err error) { - // Request structure. - request := &struct { - NewDHCPServerConfigurable string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDHCPServerConfigurable, err = soap.MarshalBoolean(NewDHCPServerConfigurable); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPServerConfigurable", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDHCPServerConfigurable: -func (client *LANHostConfigManagement1) GetDHCPServerConfigurable() (NewDHCPServerConfigurable bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDHCPServerConfigurable string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPServerConfigurable", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDHCPServerConfigurable, err = soap.UnmarshalBoolean(response.NewDHCPServerConfigurable); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDHCPRelay: -// -// -func (client *LANHostConfigManagement1) SetDHCPRelay(NewDHCPRelay bool) (err error) { - // Request structure. - request := &struct { - NewDHCPRelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDHCPRelay, err = soap.MarshalBoolean(NewDHCPRelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPRelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDHCPRelay: -func (client *LANHostConfigManagement1) GetDHCPRelay() (NewDHCPRelay bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDHCPRelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPRelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDHCPRelay, err = soap.UnmarshalBoolean(response.NewDHCPRelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewSubnetMask: -// -// -func (client *LANHostConfigManagement1) SetSubnetMask(NewSubnetMask string) (err error) { - // Request structure. - request := &struct { - NewSubnetMask string - }{} - // BEGIN Marshal arguments into request. - - if request.NewSubnetMask, err = soap.MarshalString(NewSubnetMask); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetSubnetMask", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewSubnetMask: -func (client *LANHostConfigManagement1) GetSubnetMask() (NewSubnetMask string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewSubnetMask string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetSubnetMask", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewSubnetMask, err = soap.UnmarshalString(response.NewSubnetMask); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIPRouters: -// -// -func (client *LANHostConfigManagement1) SetIPRouter(NewIPRouters string) (err error) { - // Request structure. - request := &struct { - NewIPRouters string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetIPRouter", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIPRouters: -// -// -func (client *LANHostConfigManagement1) DeleteIPRouter(NewIPRouters string) (err error) { - // Request structure. - request := &struct { - NewIPRouters string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteIPRouter", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIPRouters: -func (client *LANHostConfigManagement1) GetIPRoutersList() (NewIPRouters string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIPRouters string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetIPRoutersList", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIPRouters, err = soap.UnmarshalString(response.NewIPRouters); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDomainName: -// -// -func (client *LANHostConfigManagement1) SetDomainName(NewDomainName string) (err error) { - // Request structure. - request := &struct { - NewDomainName string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDomainName, err = soap.MarshalString(NewDomainName); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDomainName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDomainName: -func (client *LANHostConfigManagement1) GetDomainName() (NewDomainName string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDomainName string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDomainName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDomainName, err = soap.UnmarshalString(response.NewDomainName); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewMinAddress: -// -// * NewMaxAddress: -// -// -func (client *LANHostConfigManagement1) SetAddressRange(NewMinAddress string, NewMaxAddress string) (err error) { - // Request structure. - request := &struct { - NewMinAddress string - - NewMaxAddress string - }{} - // BEGIN Marshal arguments into request. - - if request.NewMinAddress, err = soap.MarshalString(NewMinAddress); err != nil { - return - } - if request.NewMaxAddress, err = soap.MarshalString(NewMaxAddress); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetAddressRange", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewMinAddress: -// -// * NewMaxAddress: -func (client *LANHostConfigManagement1) GetAddressRange() (NewMinAddress string, NewMaxAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewMinAddress string - - NewMaxAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetAddressRange", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewMinAddress, err = soap.UnmarshalString(response.NewMinAddress); err != nil { - return - } - if NewMaxAddress, err = soap.UnmarshalString(response.NewMaxAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewReservedAddresses: -// -// -func (client *LANHostConfigManagement1) SetReservedAddress(NewReservedAddresses string) (err error) { - // Request structure. - request := &struct { - NewReservedAddresses string - }{} - // BEGIN Marshal arguments into request. - - if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetReservedAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewReservedAddresses: -// -// -func (client *LANHostConfigManagement1) DeleteReservedAddress(NewReservedAddresses string) (err error) { - // Request structure. - request := &struct { - NewReservedAddresses string - }{} - // BEGIN Marshal arguments into request. - - if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteReservedAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewReservedAddresses: -func (client *LANHostConfigManagement1) GetReservedAddresses() (NewReservedAddresses string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewReservedAddresses string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetReservedAddresses", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewReservedAddresses, err = soap.UnmarshalString(response.NewReservedAddresses); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDNSServers: -// -// -func (client *LANHostConfigManagement1) SetDNSServer(NewDNSServers string) (err error) { - // Request structure. - request := &struct { - NewDNSServers string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDNSServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDNSServers: -// -// -func (client *LANHostConfigManagement1) DeleteDNSServer(NewDNSServers string) (err error) { - // Request structure. - request := &struct { - NewDNSServers string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteDNSServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDNSServers: -func (client *LANHostConfigManagement1) GetDNSServers() (NewDNSServers string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDNSServers string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDNSServers", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDNSServers, err = soap.UnmarshalString(response.NewDNSServers); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Layer3Forwarding1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:Layer3Forwarding:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type Layer3Forwarding1 struct { - goupnp.ServiceClient -} - -// NewLayer3Forwarding1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil { - return - } - clients = make([]*Layer3Forwarding1, len(genericClients)) - for i := range genericClients { - clients[i] = &Layer3Forwarding1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewDefaultConnectionService: -// -// -func (client *Layer3Forwarding1) SetDefaultConnectionService(NewDefaultConnectionService string) (err error) { - // Request structure. - request := &struct { - NewDefaultConnectionService string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDefaultConnectionService, err = soap.MarshalString(NewDefaultConnectionService); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "SetDefaultConnectionService", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDefaultConnectionService: -func (client *Layer3Forwarding1) GetDefaultConnectionService() (NewDefaultConnectionService string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDefaultConnectionService string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "GetDefaultConnectionService", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDefaultConnectionService, err = soap.UnmarshalString(response.NewDefaultConnectionService); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANCableLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCableLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANCableLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANCableLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil { - return - } - clients = make([]*WANCableLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANCableLinkConfig1{genericClients[i]} - } - return -} - -// -// -// Return values: -// -// * NewCableLinkConfigState: allowed values: notReady, dsSyncComplete, usParamAcquired, rangingComplete, ipComplete, todEstablished, paramTransferComplete, registrationComplete, operational, accessDenied -// -// * NewLinkType: allowed values: Ethernet -func (client *WANCableLinkConfig1) GetCableLinkConfigInfo() (NewCableLinkConfigState string, NewLinkType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewCableLinkConfigState string - - NewLinkType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetCableLinkConfigInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewCableLinkConfigState, err = soap.UnmarshalString(response.NewCableLinkConfigState); err != nil { - return - } - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDownstreamFrequency: -func (client *WANCableLinkConfig1) GetDownstreamFrequency() (NewDownstreamFrequency uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDownstreamFrequency string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamFrequency", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDownstreamFrequency, err = soap.UnmarshalUi4(response.NewDownstreamFrequency); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDownstreamModulation: allowed values: 64QAM, 256QAM -func (client *WANCableLinkConfig1) GetDownstreamModulation() (NewDownstreamModulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDownstreamModulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamModulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDownstreamModulation, err = soap.UnmarshalString(response.NewDownstreamModulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamFrequency: -func (client *WANCableLinkConfig1) GetUpstreamFrequency() (NewUpstreamFrequency uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamFrequency string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamFrequency", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamFrequency, err = soap.UnmarshalUi4(response.NewUpstreamFrequency); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamModulation: allowed values: QPSK, 16QAM -func (client *WANCableLinkConfig1) GetUpstreamModulation() (NewUpstreamModulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamModulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamModulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamModulation, err = soap.UnmarshalString(response.NewUpstreamModulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamChannelID: -func (client *WANCableLinkConfig1) GetUpstreamChannelID() (NewUpstreamChannelID uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamChannelID string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamChannelID", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamChannelID, err = soap.UnmarshalUi4(response.NewUpstreamChannelID); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamPowerLevel: -func (client *WANCableLinkConfig1) GetUpstreamPowerLevel() (NewUpstreamPowerLevel uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamPowerLevel string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamPowerLevel", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamPowerLevel, err = soap.UnmarshalUi4(response.NewUpstreamPowerLevel); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewBPIEncryptionEnabled: -func (client *WANCableLinkConfig1) GetBPIEncryptionEnabled() (NewBPIEncryptionEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewBPIEncryptionEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetBPIEncryptionEnabled", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewBPIEncryptionEnabled, err = soap.UnmarshalBoolean(response.NewBPIEncryptionEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConfigFile: -func (client *WANCableLinkConfig1) GetConfigFile() (NewConfigFile string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConfigFile string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetConfigFile", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConfigFile, err = soap.UnmarshalString(response.NewConfigFile); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTFTPServer: -func (client *WANCableLinkConfig1) GetTFTPServer() (NewTFTPServer string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTFTPServer string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetTFTPServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTFTPServer, err = soap.UnmarshalString(response.NewTFTPServer); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANCommonInterfaceConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANCommonInterfaceConfig1 struct { - goupnp.ServiceClient -} - -// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil { - return - } - clients = make([]*WANCommonInterfaceConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANCommonInterfaceConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewEnabledForInternet: -// -// -func (client *WANCommonInterfaceConfig1) SetEnabledForInternet(NewEnabledForInternet bool) (err error) { - // Request structure. - request := &struct { - NewEnabledForInternet string - }{} - // BEGIN Marshal arguments into request. - - if request.NewEnabledForInternet, err = soap.MarshalBoolean(NewEnabledForInternet); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "SetEnabledForInternet", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewEnabledForInternet: -func (client *WANCommonInterfaceConfig1) GetEnabledForInternet() (NewEnabledForInternet bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewEnabledForInternet string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetEnabledForInternet", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewEnabledForInternet, err = soap.UnmarshalBoolean(response.NewEnabledForInternet); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWANAccessType: allowed values: DSL, POTS, Cable, Ethernet -// -// * NewLayer1UpstreamMaxBitRate: -// -// * NewLayer1DownstreamMaxBitRate: -// -// * NewPhysicalLinkStatus: allowed values: Up, Down -func (client *WANCommonInterfaceConfig1) GetCommonLinkProperties() (NewWANAccessType string, NewLayer1UpstreamMaxBitRate uint32, NewLayer1DownstreamMaxBitRate uint32, NewPhysicalLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWANAccessType string - - NewLayer1UpstreamMaxBitRate string - - NewLayer1DownstreamMaxBitRate string - - NewPhysicalLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetCommonLinkProperties", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWANAccessType, err = soap.UnmarshalString(response.NewWANAccessType); err != nil { - return - } - if NewLayer1UpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1UpstreamMaxBitRate); err != nil { - return - } - if NewLayer1DownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1DownstreamMaxBitRate); err != nil { - return - } - if NewPhysicalLinkStatus, err = soap.UnmarshalString(response.NewPhysicalLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWANAccessProvider: -func (client *WANCommonInterfaceConfig1) GetWANAccessProvider() (NewWANAccessProvider string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWANAccessProvider string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetWANAccessProvider", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWANAccessProvider, err = soap.UnmarshalString(response.NewWANAccessProvider); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewMaximumActiveConnections: allowed value range: minimum=1, step=1 -func (client *WANCommonInterfaceConfig1) GetMaximumActiveConnections() (NewMaximumActiveConnections uint16, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewMaximumActiveConnections string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetMaximumActiveConnections", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewMaximumActiveConnections, err = soap.UnmarshalUi2(response.NewMaximumActiveConnections); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalBytesSent: -func (client *WANCommonInterfaceConfig1) GetTotalBytesSent() (NewTotalBytesSent uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalBytesSent string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesSent", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalBytesSent, err = soap.UnmarshalUi4(response.NewTotalBytesSent); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalBytesReceived: -func (client *WANCommonInterfaceConfig1) GetTotalBytesReceived() (NewTotalBytesReceived uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalBytesReceived string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesReceived", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalBytesReceived, err = soap.UnmarshalUi4(response.NewTotalBytesReceived); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalPacketsSent: -func (client *WANCommonInterfaceConfig1) GetTotalPacketsSent() (NewTotalPacketsSent uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalPacketsSent string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsSent", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalPacketsSent, err = soap.UnmarshalUi4(response.NewTotalPacketsSent); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalPacketsReceived: -func (client *WANCommonInterfaceConfig1) GetTotalPacketsReceived() (NewTotalPacketsReceived uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalPacketsReceived string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsReceived", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalPacketsReceived, err = soap.UnmarshalUi4(response.NewTotalPacketsReceived); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewActiveConnectionIndex: -// -// Return values: -// -// * NewActiveConnDeviceContainer: -// -// * NewActiveConnectionServiceID: -func (client *WANCommonInterfaceConfig1) GetActiveConnection(NewActiveConnectionIndex uint16) (NewActiveConnDeviceContainer string, NewActiveConnectionServiceID string, err error) { - // Request structure. - request := &struct { - NewActiveConnectionIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewActiveConnectionIndex, err = soap.MarshalUi2(NewActiveConnectionIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewActiveConnDeviceContainer string - - NewActiveConnectionServiceID string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetActiveConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewActiveConnDeviceContainer, err = soap.UnmarshalString(response.NewActiveConnDeviceContainer); err != nil { - return - } - if NewActiveConnectionServiceID, err = soap.UnmarshalString(response.NewActiveConnectionServiceID); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANDSLLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANDSLLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANDSLLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANDSLLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil { - return - } - clients = make([]*WANDSLLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANDSLLinkConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewLinkType: -// -// -func (client *WANDSLLinkConfig1) SetDSLLinkType(NewLinkType string) (err error) { - // Request structure. - request := &struct { - NewLinkType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDSLLinkType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewLinkType: -// -// * NewLinkStatus: allowed values: Up, Down -func (client *WANDSLLinkConfig1) GetDSLLinkInfo() (NewLinkType string, NewLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewLinkType string - - NewLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDSLLinkInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - if NewLinkStatus, err = soap.UnmarshalString(response.NewLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoConfig: -func (client *WANDSLLinkConfig1) GetAutoConfig() (NewAutoConfig bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoConfig string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetAutoConfig", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoConfig, err = soap.UnmarshalBoolean(response.NewAutoConfig); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewModulationType: -func (client *WANDSLLinkConfig1) GetModulationType() (NewModulationType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewModulationType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetModulationType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewModulationType, err = soap.UnmarshalString(response.NewModulationType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDestinationAddress: -// -// -func (client *WANDSLLinkConfig1) SetDestinationAddress(NewDestinationAddress string) (err error) { - // Request structure. - request := &struct { - NewDestinationAddress string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDestinationAddress, err = soap.MarshalString(NewDestinationAddress); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDestinationAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDestinationAddress: -func (client *WANDSLLinkConfig1) GetDestinationAddress() (NewDestinationAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDestinationAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDestinationAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDestinationAddress, err = soap.UnmarshalString(response.NewDestinationAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewATMEncapsulation: -// -// -func (client *WANDSLLinkConfig1) SetATMEncapsulation(NewATMEncapsulation string) (err error) { - // Request structure. - request := &struct { - NewATMEncapsulation string - }{} - // BEGIN Marshal arguments into request. - - if request.NewATMEncapsulation, err = soap.MarshalString(NewATMEncapsulation); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetATMEncapsulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewATMEncapsulation: -func (client *WANDSLLinkConfig1) GetATMEncapsulation() (NewATMEncapsulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewATMEncapsulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetATMEncapsulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewATMEncapsulation, err = soap.UnmarshalString(response.NewATMEncapsulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewFCSPreserved: -// -// -func (client *WANDSLLinkConfig1) SetFCSPreserved(NewFCSPreserved bool) (err error) { - // Request structure. - request := &struct { - NewFCSPreserved string - }{} - // BEGIN Marshal arguments into request. - - if request.NewFCSPreserved, err = soap.MarshalBoolean(NewFCSPreserved); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetFCSPreserved", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewFCSPreserved: -func (client *WANDSLLinkConfig1) GetFCSPreserved() (NewFCSPreserved bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewFCSPreserved string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetFCSPreserved", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewFCSPreserved, err = soap.UnmarshalBoolean(response.NewFCSPreserved); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANEthernetLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANEthernetLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil { - return - } - clients = make([]*WANEthernetLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANEthernetLinkConfig1{genericClients[i]} - } - return -} - -// -// -// Return values: -// -// * NewEthernetLinkStatus: allowed values: Up, Down -func (client *WANEthernetLinkConfig1) GetEthernetLinkStatus() (NewEthernetLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewEthernetLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANEthernetLinkConfig_1, "GetEthernetLinkStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewEthernetLinkStatus, err = soap.UnmarshalString(response.NewEthernetLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANIPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANIPConnection1 struct { - goupnp.ServiceClient -} - -// NewWANIPConnection1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil { - return - } - clients = make([]*WANIPConnection1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANIPConnection1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewConnectionType: -// -// -func (client *WANIPConnection1) SetConnectionType(NewConnectionType string) (err error) { - // Request structure. - request := &struct { - NewConnectionType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetConnectionType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionType: -// -// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, IP_Bridged -func (client *WANIPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionType string - - NewPossibleConnectionTypes string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { - return - } - if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) RequestConnection() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) RequestTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) ForceTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "ForceTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewAutoDisconnectTime: -// -// -func (client *WANIPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewAutoDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIdleDisconnectTime: -// -// -func (client *WANIPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewIdleDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewWarnDisconnectDelay: -// -// -func (client *WANIPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { - // Request structure. - request := &struct { - NewWarnDisconnectDelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected -// -// * NewLastConnectionError: allowed values: ERROR_NONE -// -// * NewUptime: -func (client *WANIPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionStatus string - - NewLastConnectionError string - - NewUptime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetStatusInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { - return - } - if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { - return - } - if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoDisconnectTime: -func (client *WANIPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIdleDisconnectTime: -func (client *WANIPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIdleDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWarnDisconnectDelay: -func (client *WANIPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWarnDisconnectDelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewRSIPAvailable: -// -// * NewNATEnabled: -func (client *WANIPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRSIPAvailable string - - NewNATEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetNATRSIPStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { - return - } - if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewPortMappingIndex: -// -// Return values: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANIPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewPortMappingIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { - return - } - if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { - return - } - if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { - return - } - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// Return values: -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANIPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -// -// -func (client *WANIPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "AddPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// -func (client *WANIPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "DeletePortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewExternalIPAddress: -func (client *WANIPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewExternalIPAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANPOTSLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANPOTSLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil { - return - } - clients = make([]*WANPOTSLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANPOTSLinkConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewISPPhoneNumber: -// -// * NewISPInfo: -// -// * NewLinkType: allowed values: PPP_Dialup -// -// -func (client *WANPOTSLinkConfig1) SetISPInfo(NewISPPhoneNumber string, NewISPInfo string, NewLinkType string) (err error) { - // Request structure. - request := &struct { - NewISPPhoneNumber string - - NewISPInfo string - - NewLinkType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewISPPhoneNumber, err = soap.MarshalString(NewISPPhoneNumber); err != nil { - return - } - if request.NewISPInfo, err = soap.MarshalString(NewISPInfo); err != nil { - return - } - if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetISPInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewNumberOfRetries: -// -// * NewDelayBetweenRetries: -// -// -func (client *WANPOTSLinkConfig1) SetCallRetryInfo(NewNumberOfRetries uint32, NewDelayBetweenRetries uint32) (err error) { - // Request structure. - request := &struct { - NewNumberOfRetries string - - NewDelayBetweenRetries string - }{} - // BEGIN Marshal arguments into request. - - if request.NewNumberOfRetries, err = soap.MarshalUi4(NewNumberOfRetries); err != nil { - return - } - if request.NewDelayBetweenRetries, err = soap.MarshalUi4(NewDelayBetweenRetries); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetCallRetryInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewISPPhoneNumber: -// -// * NewISPInfo: -// -// * NewLinkType: allowed values: PPP_Dialup -func (client *WANPOTSLinkConfig1) GetISPInfo() (NewISPPhoneNumber string, NewISPInfo string, NewLinkType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewISPPhoneNumber string - - NewISPInfo string - - NewLinkType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetISPInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewISPPhoneNumber, err = soap.UnmarshalString(response.NewISPPhoneNumber); err != nil { - return - } - if NewISPInfo, err = soap.UnmarshalString(response.NewISPInfo); err != nil { - return - } - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewNumberOfRetries: -// -// * NewDelayBetweenRetries: -func (client *WANPOTSLinkConfig1) GetCallRetryInfo() (NewNumberOfRetries uint32, NewDelayBetweenRetries uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewNumberOfRetries string - - NewDelayBetweenRetries string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetCallRetryInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewNumberOfRetries, err = soap.UnmarshalUi4(response.NewNumberOfRetries); err != nil { - return - } - if NewDelayBetweenRetries, err = soap.UnmarshalUi4(response.NewDelayBetweenRetries); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewFclass: -func (client *WANPOTSLinkConfig1) GetFclass() (NewFclass string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewFclass string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetFclass", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewFclass, err = soap.UnmarshalString(response.NewFclass); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataModulationSupported: -func (client *WANPOTSLinkConfig1) GetDataModulationSupported() (NewDataModulationSupported string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataModulationSupported string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataModulationSupported", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataModulationSupported, err = soap.UnmarshalString(response.NewDataModulationSupported); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataProtocol: -func (client *WANPOTSLinkConfig1) GetDataProtocol() (NewDataProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataProtocol, err = soap.UnmarshalString(response.NewDataProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataCompression: -func (client *WANPOTSLinkConfig1) GetDataCompression() (NewDataCompression string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataCompression string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataCompression", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataCompression, err = soap.UnmarshalString(response.NewDataCompression); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPlusVTRCommandSupported: -func (client *WANPOTSLinkConfig1) GetPlusVTRCommandSupported() (NewPlusVTRCommandSupported bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPlusVTRCommandSupported string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetPlusVTRCommandSupported", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPlusVTRCommandSupported, err = soap.UnmarshalBoolean(response.NewPlusVTRCommandSupported); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANPPPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPPPConnection:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANPPPConnection1 struct { - goupnp.ServiceClient -} - -// NewWANPPPConnection1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil { - return - } - clients = make([]*WANPPPConnection1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANPPPConnection1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewConnectionType: -// -// -func (client *WANPPPConnection1) SetConnectionType(NewConnectionType string) (err error) { - // Request structure. - request := &struct { - NewConnectionType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetConnectionType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionType: -// -// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, DHCP_Spoofed, PPPoE_Bridged, PPTP_Relay, L2TP_Relay, PPPoE_Relay -func (client *WANPPPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionType string - - NewPossibleConnectionTypes string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { - return - } - if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewUserName: -// -// * NewPassword: -// -// -func (client *WANPPPConnection1) ConfigureConnection(NewUserName string, NewPassword string) (err error) { - // Request structure. - request := &struct { - NewUserName string - - NewPassword string - }{} - // BEGIN Marshal arguments into request. - - if request.NewUserName, err = soap.MarshalString(NewUserName); err != nil { - return - } - if request.NewPassword, err = soap.MarshalString(NewPassword); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ConfigureConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) RequestConnection() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) RequestTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) ForceTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ForceTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewAutoDisconnectTime: -// -// -func (client *WANPPPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewAutoDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIdleDisconnectTime: -// -// -func (client *WANPPPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewIdleDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewWarnDisconnectDelay: -// -// -func (client *WANPPPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { - // Request structure. - request := &struct { - NewWarnDisconnectDelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected -// -// * NewLastConnectionError: allowed values: ERROR_NONE -// -// * NewUptime: -func (client *WANPPPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionStatus string - - NewLastConnectionError string - - NewUptime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetStatusInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { - return - } - if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { - return - } - if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamMaxBitRate: -// -// * NewDownstreamMaxBitRate: -func (client *WANPPPConnection1) GetLinkLayerMaxBitRates() (NewUpstreamMaxBitRate uint32, NewDownstreamMaxBitRate uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamMaxBitRate string - - NewDownstreamMaxBitRate string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetLinkLayerMaxBitRates", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewUpstreamMaxBitRate); err != nil { - return - } - if NewDownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewDownstreamMaxBitRate); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPEncryptionProtocol: -func (client *WANPPPConnection1) GetPPPEncryptionProtocol() (NewPPPEncryptionProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPEncryptionProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPEncryptionProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPEncryptionProtocol, err = soap.UnmarshalString(response.NewPPPEncryptionProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPCompressionProtocol: -func (client *WANPPPConnection1) GetPPPCompressionProtocol() (NewPPPCompressionProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPCompressionProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPCompressionProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPCompressionProtocol, err = soap.UnmarshalString(response.NewPPPCompressionProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPAuthenticationProtocol: -func (client *WANPPPConnection1) GetPPPAuthenticationProtocol() (NewPPPAuthenticationProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPAuthenticationProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPAuthenticationProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPAuthenticationProtocol, err = soap.UnmarshalString(response.NewPPPAuthenticationProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUserName: -func (client *WANPPPConnection1) GetUserName() (NewUserName string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUserName string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetUserName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUserName, err = soap.UnmarshalString(response.NewUserName); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPassword: -func (client *WANPPPConnection1) GetPassword() (NewPassword string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPassword string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPassword", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPassword, err = soap.UnmarshalString(response.NewPassword); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoDisconnectTime: -func (client *WANPPPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIdleDisconnectTime: -func (client *WANPPPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIdleDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWarnDisconnectDelay: -func (client *WANPPPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWarnDisconnectDelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewRSIPAvailable: -// -// * NewNATEnabled: -func (client *WANPPPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRSIPAvailable string - - NewNATEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetNATRSIPStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { - return - } - if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewPortMappingIndex: -// -// Return values: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANPPPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewPortMappingIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { - return - } - if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { - return - } - if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { - return - } - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// Return values: -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANPPPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -// -// -func (client *WANPPPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "AddPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// -func (client *WANPPPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "DeletePortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewExternalIPAddress: -func (client *WANPPPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewExternalIPAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go b/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go deleted file mode 100644 index 2c4799171..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway2/internetgateway2.go +++ /dev/null @@ -1,5271 +0,0 @@ -// Client for UPnP Device Control Protocol Internet Gateway Device v2. -// -// This DCP is documented in detail at: http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf -// -// Typically, use one of the New* functions to discover services on the local -// network. -package internetgateway2 - -// Generated file - do not edit by hand. See README.md - -import ( - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/soap" -) - -// Hack to avoid Go complaining if time isn't used. -var _ time.Time - -// Device URNs: -const ( - URN_LANDevice_1 = "urn:schemas-upnp-org:device:LANDevice:1" - URN_WANConnectionDevice_1 = "urn:schemas-upnp-org:device:WANConnectionDevice:1" - URN_WANConnectionDevice_2 = "urn:schemas-upnp-org:device:WANConnectionDevice:2" - URN_WANDevice_1 = "urn:schemas-upnp-org:device:WANDevice:1" - URN_WANDevice_2 = "urn:schemas-upnp-org:device:WANDevice:2" -) - -// Service URNs: -const ( - URN_LANHostConfigManagement_1 = "urn:schemas-upnp-org:service:LANHostConfigManagement:1" - URN_Layer3Forwarding_1 = "urn:schemas-upnp-org:service:Layer3Forwarding:1" - URN_WANCableLinkConfig_1 = "urn:schemas-upnp-org:service:WANCableLinkConfig:1" - URN_WANCommonInterfaceConfig_1 = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" - URN_WANDSLLinkConfig_1 = "urn:schemas-upnp-org:service:WANDSLLinkConfig:1" - URN_WANEthernetLinkConfig_1 = "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" - URN_WANIPConnection_1 = "urn:schemas-upnp-org:service:WANIPConnection:1" - URN_WANIPConnection_2 = "urn:schemas-upnp-org:service:WANIPConnection:2" - URN_WANIPv6FirewallControl_1 = "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" - URN_WANPOTSLinkConfig_1 = "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1" - URN_WANPPPConnection_1 = "urn:schemas-upnp-org:service:WANPPPConnection:1" -) - -// LANHostConfigManagement1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:LANHostConfigManagement:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type LANHostConfigManagement1 struct { - goupnp.ServiceClient -} - -// NewLANHostConfigManagement1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewLANHostConfigManagement1Clients() (clients []*LANHostConfigManagement1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_LANHostConfigManagement_1); err != nil { - return - } - clients = make([]*LANHostConfigManagement1, len(genericClients)) - for i := range genericClients { - clients[i] = &LANHostConfigManagement1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewDHCPServerConfigurable: -// -// -func (client *LANHostConfigManagement1) SetDHCPServerConfigurable(NewDHCPServerConfigurable bool) (err error) { - // Request structure. - request := &struct { - NewDHCPServerConfigurable string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDHCPServerConfigurable, err = soap.MarshalBoolean(NewDHCPServerConfigurable); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPServerConfigurable", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDHCPServerConfigurable: -func (client *LANHostConfigManagement1) GetDHCPServerConfigurable() (NewDHCPServerConfigurable bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDHCPServerConfigurable string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPServerConfigurable", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDHCPServerConfigurable, err = soap.UnmarshalBoolean(response.NewDHCPServerConfigurable); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDHCPRelay: -// -// -func (client *LANHostConfigManagement1) SetDHCPRelay(NewDHCPRelay bool) (err error) { - // Request structure. - request := &struct { - NewDHCPRelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDHCPRelay, err = soap.MarshalBoolean(NewDHCPRelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDHCPRelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDHCPRelay: -func (client *LANHostConfigManagement1) GetDHCPRelay() (NewDHCPRelay bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDHCPRelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDHCPRelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDHCPRelay, err = soap.UnmarshalBoolean(response.NewDHCPRelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewSubnetMask: -// -// -func (client *LANHostConfigManagement1) SetSubnetMask(NewSubnetMask string) (err error) { - // Request structure. - request := &struct { - NewSubnetMask string - }{} - // BEGIN Marshal arguments into request. - - if request.NewSubnetMask, err = soap.MarshalString(NewSubnetMask); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetSubnetMask", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewSubnetMask: -func (client *LANHostConfigManagement1) GetSubnetMask() (NewSubnetMask string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewSubnetMask string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetSubnetMask", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewSubnetMask, err = soap.UnmarshalString(response.NewSubnetMask); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIPRouters: -// -// -func (client *LANHostConfigManagement1) SetIPRouter(NewIPRouters string) (err error) { - // Request structure. - request := &struct { - NewIPRouters string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetIPRouter", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIPRouters: -// -// -func (client *LANHostConfigManagement1) DeleteIPRouter(NewIPRouters string) (err error) { - // Request structure. - request := &struct { - NewIPRouters string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIPRouters, err = soap.MarshalString(NewIPRouters); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteIPRouter", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIPRouters: -func (client *LANHostConfigManagement1) GetIPRoutersList() (NewIPRouters string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIPRouters string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetIPRoutersList", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIPRouters, err = soap.UnmarshalString(response.NewIPRouters); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDomainName: -// -// -func (client *LANHostConfigManagement1) SetDomainName(NewDomainName string) (err error) { - // Request structure. - request := &struct { - NewDomainName string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDomainName, err = soap.MarshalString(NewDomainName); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDomainName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDomainName: -func (client *LANHostConfigManagement1) GetDomainName() (NewDomainName string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDomainName string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDomainName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDomainName, err = soap.UnmarshalString(response.NewDomainName); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewMinAddress: -// -// * NewMaxAddress: -// -// -func (client *LANHostConfigManagement1) SetAddressRange(NewMinAddress string, NewMaxAddress string) (err error) { - // Request structure. - request := &struct { - NewMinAddress string - - NewMaxAddress string - }{} - // BEGIN Marshal arguments into request. - - if request.NewMinAddress, err = soap.MarshalString(NewMinAddress); err != nil { - return - } - if request.NewMaxAddress, err = soap.MarshalString(NewMaxAddress); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetAddressRange", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewMinAddress: -// -// * NewMaxAddress: -func (client *LANHostConfigManagement1) GetAddressRange() (NewMinAddress string, NewMaxAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewMinAddress string - - NewMaxAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetAddressRange", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewMinAddress, err = soap.UnmarshalString(response.NewMinAddress); err != nil { - return - } - if NewMaxAddress, err = soap.UnmarshalString(response.NewMaxAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewReservedAddresses: -// -// -func (client *LANHostConfigManagement1) SetReservedAddress(NewReservedAddresses string) (err error) { - // Request structure. - request := &struct { - NewReservedAddresses string - }{} - // BEGIN Marshal arguments into request. - - if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetReservedAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewReservedAddresses: -// -// -func (client *LANHostConfigManagement1) DeleteReservedAddress(NewReservedAddresses string) (err error) { - // Request structure. - request := &struct { - NewReservedAddresses string - }{} - // BEGIN Marshal arguments into request. - - if request.NewReservedAddresses, err = soap.MarshalString(NewReservedAddresses); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteReservedAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewReservedAddresses: -func (client *LANHostConfigManagement1) GetReservedAddresses() (NewReservedAddresses string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewReservedAddresses string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetReservedAddresses", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewReservedAddresses, err = soap.UnmarshalString(response.NewReservedAddresses); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDNSServers: -// -// -func (client *LANHostConfigManagement1) SetDNSServer(NewDNSServers string) (err error) { - // Request structure. - request := &struct { - NewDNSServers string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "SetDNSServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDNSServers: -// -// -func (client *LANHostConfigManagement1) DeleteDNSServer(NewDNSServers string) (err error) { - // Request structure. - request := &struct { - NewDNSServers string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDNSServers, err = soap.MarshalString(NewDNSServers); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "DeleteDNSServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDNSServers: -func (client *LANHostConfigManagement1) GetDNSServers() (NewDNSServers string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDNSServers string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_LANHostConfigManagement_1, "GetDNSServers", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDNSServers, err = soap.UnmarshalString(response.NewDNSServers); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Layer3Forwarding1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:Layer3Forwarding:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type Layer3Forwarding1 struct { - goupnp.ServiceClient -} - -// NewLayer3Forwarding1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewLayer3Forwarding1Clients() (clients []*Layer3Forwarding1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_Layer3Forwarding_1); err != nil { - return - } - clients = make([]*Layer3Forwarding1, len(genericClients)) - for i := range genericClients { - clients[i] = &Layer3Forwarding1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewDefaultConnectionService: -// -// -func (client *Layer3Forwarding1) SetDefaultConnectionService(NewDefaultConnectionService string) (err error) { - // Request structure. - request := &struct { - NewDefaultConnectionService string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDefaultConnectionService, err = soap.MarshalString(NewDefaultConnectionService); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "SetDefaultConnectionService", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDefaultConnectionService: -func (client *Layer3Forwarding1) GetDefaultConnectionService() (NewDefaultConnectionService string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDefaultConnectionService string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_Layer3Forwarding_1, "GetDefaultConnectionService", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDefaultConnectionService, err = soap.UnmarshalString(response.NewDefaultConnectionService); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANCableLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCableLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANCableLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANCableLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANCableLinkConfig1Clients() (clients []*WANCableLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCableLinkConfig_1); err != nil { - return - } - clients = make([]*WANCableLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANCableLinkConfig1{genericClients[i]} - } - return -} - -// -// -// Return values: -// -// * NewCableLinkConfigState: allowed values: notReady, dsSyncComplete, usParamAcquired, rangingComplete, ipComplete, todEstablished, paramTransferComplete, registrationComplete, operational, accessDenied -// -// * NewLinkType: allowed values: Ethernet -func (client *WANCableLinkConfig1) GetCableLinkConfigInfo() (NewCableLinkConfigState string, NewLinkType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewCableLinkConfigState string - - NewLinkType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetCableLinkConfigInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewCableLinkConfigState, err = soap.UnmarshalString(response.NewCableLinkConfigState); err != nil { - return - } - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDownstreamFrequency: -func (client *WANCableLinkConfig1) GetDownstreamFrequency() (NewDownstreamFrequency uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDownstreamFrequency string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamFrequency", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDownstreamFrequency, err = soap.UnmarshalUi4(response.NewDownstreamFrequency); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDownstreamModulation: allowed values: 64QAM, 256QAM -func (client *WANCableLinkConfig1) GetDownstreamModulation() (NewDownstreamModulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDownstreamModulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetDownstreamModulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDownstreamModulation, err = soap.UnmarshalString(response.NewDownstreamModulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamFrequency: -func (client *WANCableLinkConfig1) GetUpstreamFrequency() (NewUpstreamFrequency uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamFrequency string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamFrequency", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamFrequency, err = soap.UnmarshalUi4(response.NewUpstreamFrequency); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamModulation: allowed values: QPSK, 16QAM -func (client *WANCableLinkConfig1) GetUpstreamModulation() (NewUpstreamModulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamModulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamModulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamModulation, err = soap.UnmarshalString(response.NewUpstreamModulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamChannelID: -func (client *WANCableLinkConfig1) GetUpstreamChannelID() (NewUpstreamChannelID uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamChannelID string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamChannelID", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamChannelID, err = soap.UnmarshalUi4(response.NewUpstreamChannelID); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamPowerLevel: -func (client *WANCableLinkConfig1) GetUpstreamPowerLevel() (NewUpstreamPowerLevel uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamPowerLevel string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetUpstreamPowerLevel", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamPowerLevel, err = soap.UnmarshalUi4(response.NewUpstreamPowerLevel); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewBPIEncryptionEnabled: -func (client *WANCableLinkConfig1) GetBPIEncryptionEnabled() (NewBPIEncryptionEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewBPIEncryptionEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetBPIEncryptionEnabled", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewBPIEncryptionEnabled, err = soap.UnmarshalBoolean(response.NewBPIEncryptionEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConfigFile: -func (client *WANCableLinkConfig1) GetConfigFile() (NewConfigFile string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConfigFile string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetConfigFile", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConfigFile, err = soap.UnmarshalString(response.NewConfigFile); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTFTPServer: -func (client *WANCableLinkConfig1) GetTFTPServer() (NewTFTPServer string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTFTPServer string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCableLinkConfig_1, "GetTFTPServer", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTFTPServer, err = soap.UnmarshalString(response.NewTFTPServer); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANCommonInterfaceConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANCommonInterfaceConfig1 struct { - goupnp.ServiceClient -} - -// NewWANCommonInterfaceConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANCommonInterfaceConfig1Clients() (clients []*WANCommonInterfaceConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANCommonInterfaceConfig_1); err != nil { - return - } - clients = make([]*WANCommonInterfaceConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANCommonInterfaceConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewEnabledForInternet: -// -// -func (client *WANCommonInterfaceConfig1) SetEnabledForInternet(NewEnabledForInternet bool) (err error) { - // Request structure. - request := &struct { - NewEnabledForInternet string - }{} - // BEGIN Marshal arguments into request. - - if request.NewEnabledForInternet, err = soap.MarshalBoolean(NewEnabledForInternet); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "SetEnabledForInternet", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewEnabledForInternet: -func (client *WANCommonInterfaceConfig1) GetEnabledForInternet() (NewEnabledForInternet bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewEnabledForInternet string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetEnabledForInternet", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewEnabledForInternet, err = soap.UnmarshalBoolean(response.NewEnabledForInternet); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWANAccessType: allowed values: DSL, POTS, Cable, Ethernet -// -// * NewLayer1UpstreamMaxBitRate: -// -// * NewLayer1DownstreamMaxBitRate: -// -// * NewPhysicalLinkStatus: allowed values: Up, Down -func (client *WANCommonInterfaceConfig1) GetCommonLinkProperties() (NewWANAccessType string, NewLayer1UpstreamMaxBitRate uint32, NewLayer1DownstreamMaxBitRate uint32, NewPhysicalLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWANAccessType string - - NewLayer1UpstreamMaxBitRate string - - NewLayer1DownstreamMaxBitRate string - - NewPhysicalLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetCommonLinkProperties", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWANAccessType, err = soap.UnmarshalString(response.NewWANAccessType); err != nil { - return - } - if NewLayer1UpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1UpstreamMaxBitRate); err != nil { - return - } - if NewLayer1DownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewLayer1DownstreamMaxBitRate); err != nil { - return - } - if NewPhysicalLinkStatus, err = soap.UnmarshalString(response.NewPhysicalLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWANAccessProvider: -func (client *WANCommonInterfaceConfig1) GetWANAccessProvider() (NewWANAccessProvider string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWANAccessProvider string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetWANAccessProvider", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWANAccessProvider, err = soap.UnmarshalString(response.NewWANAccessProvider); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewMaximumActiveConnections: allowed value range: minimum=1, step=1 -func (client *WANCommonInterfaceConfig1) GetMaximumActiveConnections() (NewMaximumActiveConnections uint16, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewMaximumActiveConnections string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetMaximumActiveConnections", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewMaximumActiveConnections, err = soap.UnmarshalUi2(response.NewMaximumActiveConnections); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalBytesSent: -func (client *WANCommonInterfaceConfig1) GetTotalBytesSent() (NewTotalBytesSent uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalBytesSent string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesSent", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalBytesSent, err = soap.UnmarshalUi4(response.NewTotalBytesSent); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalBytesReceived: -func (client *WANCommonInterfaceConfig1) GetTotalBytesReceived() (NewTotalBytesReceived uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalBytesReceived string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalBytesReceived", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalBytesReceived, err = soap.UnmarshalUi4(response.NewTotalBytesReceived); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalPacketsSent: -func (client *WANCommonInterfaceConfig1) GetTotalPacketsSent() (NewTotalPacketsSent uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalPacketsSent string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsSent", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalPacketsSent, err = soap.UnmarshalUi4(response.NewTotalPacketsSent); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewTotalPacketsReceived: -func (client *WANCommonInterfaceConfig1) GetTotalPacketsReceived() (NewTotalPacketsReceived uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewTotalPacketsReceived string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetTotalPacketsReceived", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewTotalPacketsReceived, err = soap.UnmarshalUi4(response.NewTotalPacketsReceived); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewActiveConnectionIndex: -// -// Return values: -// -// * NewActiveConnDeviceContainer: -// -// * NewActiveConnectionServiceID: -func (client *WANCommonInterfaceConfig1) GetActiveConnection(NewActiveConnectionIndex uint16) (NewActiveConnDeviceContainer string, NewActiveConnectionServiceID string, err error) { - // Request structure. - request := &struct { - NewActiveConnectionIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewActiveConnectionIndex, err = soap.MarshalUi2(NewActiveConnectionIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewActiveConnDeviceContainer string - - NewActiveConnectionServiceID string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANCommonInterfaceConfig_1, "GetActiveConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewActiveConnDeviceContainer, err = soap.UnmarshalString(response.NewActiveConnDeviceContainer); err != nil { - return - } - if NewActiveConnectionServiceID, err = soap.UnmarshalString(response.NewActiveConnectionServiceID); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANDSLLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANDSLLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANDSLLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANDSLLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANDSLLinkConfig1Clients() (clients []*WANDSLLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANDSLLinkConfig_1); err != nil { - return - } - clients = make([]*WANDSLLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANDSLLinkConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewLinkType: -// -// -func (client *WANDSLLinkConfig1) SetDSLLinkType(NewLinkType string) (err error) { - // Request structure. - request := &struct { - NewLinkType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDSLLinkType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewLinkType: -// -// * NewLinkStatus: allowed values: Up, Down -func (client *WANDSLLinkConfig1) GetDSLLinkInfo() (NewLinkType string, NewLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewLinkType string - - NewLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDSLLinkInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - if NewLinkStatus, err = soap.UnmarshalString(response.NewLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoConfig: -func (client *WANDSLLinkConfig1) GetAutoConfig() (NewAutoConfig bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoConfig string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetAutoConfig", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoConfig, err = soap.UnmarshalBoolean(response.NewAutoConfig); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewModulationType: -func (client *WANDSLLinkConfig1) GetModulationType() (NewModulationType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewModulationType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetModulationType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewModulationType, err = soap.UnmarshalString(response.NewModulationType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewDestinationAddress: -// -// -func (client *WANDSLLinkConfig1) SetDestinationAddress(NewDestinationAddress string) (err error) { - // Request structure. - request := &struct { - NewDestinationAddress string - }{} - // BEGIN Marshal arguments into request. - - if request.NewDestinationAddress, err = soap.MarshalString(NewDestinationAddress); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetDestinationAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDestinationAddress: -func (client *WANDSLLinkConfig1) GetDestinationAddress() (NewDestinationAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDestinationAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetDestinationAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDestinationAddress, err = soap.UnmarshalString(response.NewDestinationAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewATMEncapsulation: -// -// -func (client *WANDSLLinkConfig1) SetATMEncapsulation(NewATMEncapsulation string) (err error) { - // Request structure. - request := &struct { - NewATMEncapsulation string - }{} - // BEGIN Marshal arguments into request. - - if request.NewATMEncapsulation, err = soap.MarshalString(NewATMEncapsulation); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetATMEncapsulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewATMEncapsulation: -func (client *WANDSLLinkConfig1) GetATMEncapsulation() (NewATMEncapsulation string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewATMEncapsulation string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetATMEncapsulation", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewATMEncapsulation, err = soap.UnmarshalString(response.NewATMEncapsulation); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewFCSPreserved: -// -// -func (client *WANDSLLinkConfig1) SetFCSPreserved(NewFCSPreserved bool) (err error) { - // Request structure. - request := &struct { - NewFCSPreserved string - }{} - // BEGIN Marshal arguments into request. - - if request.NewFCSPreserved, err = soap.MarshalBoolean(NewFCSPreserved); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "SetFCSPreserved", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewFCSPreserved: -func (client *WANDSLLinkConfig1) GetFCSPreserved() (NewFCSPreserved bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewFCSPreserved string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANDSLLinkConfig_1, "GetFCSPreserved", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewFCSPreserved, err = soap.UnmarshalBoolean(response.NewFCSPreserved); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANEthernetLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANEthernetLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANEthernetLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANEthernetLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANEthernetLinkConfig1Clients() (clients []*WANEthernetLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANEthernetLinkConfig_1); err != nil { - return - } - clients = make([]*WANEthernetLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANEthernetLinkConfig1{genericClients[i]} - } - return -} - -// -// -// Return values: -// -// * NewEthernetLinkStatus: allowed values: Up, Down -func (client *WANEthernetLinkConfig1) GetEthernetLinkStatus() (NewEthernetLinkStatus string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewEthernetLinkStatus string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANEthernetLinkConfig_1, "GetEthernetLinkStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewEthernetLinkStatus, err = soap.UnmarshalString(response.NewEthernetLinkStatus); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANIPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANIPConnection1 struct { - goupnp.ServiceClient -} - -// NewWANIPConnection1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANIPConnection1Clients() (clients []*WANIPConnection1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_1); err != nil { - return - } - clients = make([]*WANIPConnection1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANIPConnection1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewConnectionType: -// -// -func (client *WANIPConnection1) SetConnectionType(NewConnectionType string) (err error) { - // Request structure. - request := &struct { - NewConnectionType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetConnectionType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionType: -// -// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, IP_Bridged -func (client *WANIPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionType string - - NewPossibleConnectionTypes string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { - return - } - if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) RequestConnection() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) RequestTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "RequestTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection1) ForceTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "ForceTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewAutoDisconnectTime: -// -// -func (client *WANIPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewAutoDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIdleDisconnectTime: -// -// -func (client *WANIPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewIdleDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewWarnDisconnectDelay: -// -// -func (client *WANIPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { - // Request structure. - request := &struct { - NewWarnDisconnectDelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected -// -// * NewLastConnectionError: allowed values: ERROR_NONE -// -// * NewUptime: -func (client *WANIPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionStatus string - - NewLastConnectionError string - - NewUptime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetStatusInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { - return - } - if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { - return - } - if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoDisconnectTime: -func (client *WANIPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIdleDisconnectTime: -func (client *WANIPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIdleDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWarnDisconnectDelay: -func (client *WANIPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWarnDisconnectDelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewRSIPAvailable: -// -// * NewNATEnabled: -func (client *WANIPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRSIPAvailable string - - NewNATEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetNATRSIPStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { - return - } - if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewPortMappingIndex: -// -// Return values: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANIPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewPortMappingIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { - return - } - if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { - return - } - if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { - return - } - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// Return values: -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANIPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -// -// -func (client *WANIPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "AddPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// -func (client *WANIPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "DeletePortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewExternalIPAddress: -func (client *WANIPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewExternalIPAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANIPConnection2 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPConnection:2". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANIPConnection2 struct { - goupnp.ServiceClient -} - -// NewWANIPConnection2Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANIPConnection2Clients() (clients []*WANIPConnection2, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPConnection_2); err != nil { - return - } - clients = make([]*WANIPConnection2, len(genericClients)) - for i := range genericClients { - clients[i] = &WANIPConnection2{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewConnectionType: allowed values: Unconfigured, IP_Routed, IP_Bridged -// -// -func (client *WANIPConnection2) SetConnectionType(NewConnectionType string) (err error) { - // Request structure. - request := &struct { - NewConnectionType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetConnectionType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionType: allowed values: Unconfigured, IP_Routed, IP_Bridged -// -// * NewPossibleConnectionTypes: -func (client *WANIPConnection2) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionType string - - NewPossibleConnectionTypes string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetConnectionTypeInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { - return - } - if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection2) RequestConnection() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "RequestConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection2) RequestTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "RequestTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANIPConnection2) ForceTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "ForceTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewAutoDisconnectTime: -// -// -func (client *WANIPConnection2) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewAutoDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIdleDisconnectTime: -// -// -func (client *WANIPConnection2) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewIdleDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewWarnDisconnectDelay: -// -// -func (client *WANIPConnection2) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { - // Request structure. - request := &struct { - NewWarnDisconnectDelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "SetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected -// -// * NewLastConnectionError: allowed values: ERROR_NONE -// -// * NewUptime: -func (client *WANIPConnection2) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionStatus string - - NewLastConnectionError string - - NewUptime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetStatusInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { - return - } - if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { - return - } - if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoDisconnectTime: -func (client *WANIPConnection2) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIdleDisconnectTime: -func (client *WANIPConnection2) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIdleDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWarnDisconnectDelay: -func (client *WANIPConnection2) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWarnDisconnectDelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewRSIPAvailable: -// -// * NewNATEnabled: -func (client *WANIPConnection2) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRSIPAvailable string - - NewNATEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetNATRSIPStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { - return - } - if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewPortMappingIndex: -// -// Return values: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: allowed value range: minimum=1, maximum=65535 -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 -func (client *WANIPConnection2) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewPortMappingIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetGenericPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { - return - } - if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { - return - } - if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { - return - } - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// Return values: -// -// * NewInternalPort: allowed value range: minimum=1, maximum=65535 -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 -func (client *WANIPConnection2) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetSpecificPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: allowed value range: minimum=1, maximum=65535 -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 -// -// -func (client *WANIPConnection2) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "AddPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// -func (client *WANIPConnection2) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "DeletePortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewStartPort: -// -// * NewEndPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewManage: -// -// -func (client *WANIPConnection2) DeletePortMappingRange(NewStartPort uint16, NewEndPort uint16, NewProtocol string, NewManage bool) (err error) { - // Request structure. - request := &struct { - NewStartPort string - - NewEndPort string - - NewProtocol string - - NewManage string - }{} - // BEGIN Marshal arguments into request. - - if request.NewStartPort, err = soap.MarshalUi2(NewStartPort); err != nil { - return - } - if request.NewEndPort, err = soap.MarshalUi2(NewEndPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewManage, err = soap.MarshalBoolean(NewManage); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "DeletePortMappingRange", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewExternalIPAddress: -func (client *WANIPConnection2) GetExternalIPAddress() (NewExternalIPAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewExternalIPAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetExternalIPAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewStartPort: -// -// * NewEndPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewManage: -// -// * NewNumberOfPorts: -// -// Return values: -// -// * NewPortListing: -func (client *WANIPConnection2) GetListOfPortMappings(NewStartPort uint16, NewEndPort uint16, NewProtocol string, NewManage bool, NewNumberOfPorts uint16) (NewPortListing string, err error) { - // Request structure. - request := &struct { - NewStartPort string - - NewEndPort string - - NewProtocol string - - NewManage string - - NewNumberOfPorts string - }{} - // BEGIN Marshal arguments into request. - - if request.NewStartPort, err = soap.MarshalUi2(NewStartPort); err != nil { - return - } - if request.NewEndPort, err = soap.MarshalUi2(NewEndPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewManage, err = soap.MarshalBoolean(NewManage); err != nil { - return - } - if request.NewNumberOfPorts, err = soap.MarshalUi2(NewNumberOfPorts); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPortListing string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "GetListOfPortMappings", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPortListing, err = soap.UnmarshalString(response.NewPortListing); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: allowed value range: minimum=1, maximum=65535 -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: allowed value range: minimum=0, maximum=604800 -// -// Return values: -// -// * NewReservedPort: -func (client *WANIPConnection2) AddAnyPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (NewReservedPort uint16, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewReservedPort string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPConnection_2, "AddAnyPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewReservedPort, err = soap.UnmarshalUi2(response.NewReservedPort); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANIPv6FirewallControl1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANIPv6FirewallControl1 struct { - goupnp.ServiceClient -} - -// NewWANIPv6FirewallControl1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANIPv6FirewallControl1Clients() (clients []*WANIPv6FirewallControl1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANIPv6FirewallControl_1); err != nil { - return - } - clients = make([]*WANIPv6FirewallControl1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANIPv6FirewallControl1{genericClients[i]} - } - return -} - -// -// -// Return values: -// -// * FirewallEnabled: -// -// * InboundPinholeAllowed: -func (client *WANIPv6FirewallControl1) GetFirewallStatus() (FirewallEnabled bool, InboundPinholeAllowed bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - FirewallEnabled string - - InboundPinholeAllowed string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetFirewallStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if FirewallEnabled, err = soap.UnmarshalBoolean(response.FirewallEnabled); err != nil { - return - } - if InboundPinholeAllowed, err = soap.UnmarshalBoolean(response.InboundPinholeAllowed); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * RemoteHost: -// -// * RemotePort: -// -// * InternalClient: -// -// * InternalPort: -// -// * Protocol: -// -// Return values: -// -// * OutboundPinholeTimeout: -func (client *WANIPv6FirewallControl1) GetOutboundPinholeTimeout(RemoteHost string, RemotePort uint16, InternalClient string, InternalPort uint16, Protocol uint16) (OutboundPinholeTimeout uint32, err error) { - // Request structure. - request := &struct { - RemoteHost string - - RemotePort string - - InternalClient string - - InternalPort string - - Protocol string - }{} - // BEGIN Marshal arguments into request. - - if request.RemoteHost, err = soap.MarshalString(RemoteHost); err != nil { - return - } - if request.RemotePort, err = soap.MarshalUi2(RemotePort); err != nil { - return - } - if request.InternalClient, err = soap.MarshalString(InternalClient); err != nil { - return - } - if request.InternalPort, err = soap.MarshalUi2(InternalPort); err != nil { - return - } - if request.Protocol, err = soap.MarshalUi2(Protocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - OutboundPinholeTimeout string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetOutboundPinholeTimeout", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if OutboundPinholeTimeout, err = soap.UnmarshalUi4(response.OutboundPinholeTimeout); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * RemoteHost: -// -// * RemotePort: -// -// * InternalClient: -// -// * InternalPort: -// -// * Protocol: -// -// * LeaseTime: allowed value range: minimum=1, maximum=86400 -// -// Return values: -// -// * UniqueID: -func (client *WANIPv6FirewallControl1) AddPinhole(RemoteHost string, RemotePort uint16, InternalClient string, InternalPort uint16, Protocol uint16, LeaseTime uint32) (UniqueID uint16, err error) { - // Request structure. - request := &struct { - RemoteHost string - - RemotePort string - - InternalClient string - - InternalPort string - - Protocol string - - LeaseTime string - }{} - // BEGIN Marshal arguments into request. - - if request.RemoteHost, err = soap.MarshalString(RemoteHost); err != nil { - return - } - if request.RemotePort, err = soap.MarshalUi2(RemotePort); err != nil { - return - } - if request.InternalClient, err = soap.MarshalString(InternalClient); err != nil { - return - } - if request.InternalPort, err = soap.MarshalUi2(InternalPort); err != nil { - return - } - if request.Protocol, err = soap.MarshalUi2(Protocol); err != nil { - return - } - if request.LeaseTime, err = soap.MarshalUi4(LeaseTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - UniqueID string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "AddPinhole", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if UniqueID, err = soap.UnmarshalUi2(response.UniqueID); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * UniqueID: -// -// * NewLeaseTime: allowed value range: minimum=1, maximum=86400 -// -// -func (client *WANIPv6FirewallControl1) UpdatePinhole(UniqueID uint16, NewLeaseTime uint32) (err error) { - // Request structure. - request := &struct { - UniqueID string - - NewLeaseTime string - }{} - // BEGIN Marshal arguments into request. - - if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { - return - } - if request.NewLeaseTime, err = soap.MarshalUi4(NewLeaseTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "UpdatePinhole", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * UniqueID: -// -// -func (client *WANIPv6FirewallControl1) DeletePinhole(UniqueID uint16) (err error) { - // Request structure. - request := &struct { - UniqueID string - }{} - // BEGIN Marshal arguments into request. - - if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "DeletePinhole", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * UniqueID: -// -// Return values: -// -// * PinholePackets: -func (client *WANIPv6FirewallControl1) GetPinholePackets(UniqueID uint16) (PinholePackets uint32, err error) { - // Request structure. - request := &struct { - UniqueID string - }{} - // BEGIN Marshal arguments into request. - - if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - PinholePackets string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "GetPinholePackets", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if PinholePackets, err = soap.UnmarshalUi4(response.PinholePackets); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * UniqueID: -// -// Return values: -// -// * IsWorking: -func (client *WANIPv6FirewallControl1) CheckPinholeWorking(UniqueID uint16) (IsWorking bool, err error) { - // Request structure. - request := &struct { - UniqueID string - }{} - // BEGIN Marshal arguments into request. - - if request.UniqueID, err = soap.MarshalUi2(UniqueID); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - IsWorking string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANIPv6FirewallControl_1, "CheckPinholeWorking", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if IsWorking, err = soap.UnmarshalBoolean(response.IsWorking); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANPOTSLinkConfig1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPOTSLinkConfig:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANPOTSLinkConfig1 struct { - goupnp.ServiceClient -} - -// NewWANPOTSLinkConfig1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANPOTSLinkConfig1Clients() (clients []*WANPOTSLinkConfig1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPOTSLinkConfig_1); err != nil { - return - } - clients = make([]*WANPOTSLinkConfig1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANPOTSLinkConfig1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewISPPhoneNumber: -// -// * NewISPInfo: -// -// * NewLinkType: allowed values: PPP_Dialup -// -// -func (client *WANPOTSLinkConfig1) SetISPInfo(NewISPPhoneNumber string, NewISPInfo string, NewLinkType string) (err error) { - // Request structure. - request := &struct { - NewISPPhoneNumber string - - NewISPInfo string - - NewLinkType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewISPPhoneNumber, err = soap.MarshalString(NewISPPhoneNumber); err != nil { - return - } - if request.NewISPInfo, err = soap.MarshalString(NewISPInfo); err != nil { - return - } - if request.NewLinkType, err = soap.MarshalString(NewLinkType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetISPInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewNumberOfRetries: -// -// * NewDelayBetweenRetries: -// -// -func (client *WANPOTSLinkConfig1) SetCallRetryInfo(NewNumberOfRetries uint32, NewDelayBetweenRetries uint32) (err error) { - // Request structure. - request := &struct { - NewNumberOfRetries string - - NewDelayBetweenRetries string - }{} - // BEGIN Marshal arguments into request. - - if request.NewNumberOfRetries, err = soap.MarshalUi4(NewNumberOfRetries); err != nil { - return - } - if request.NewDelayBetweenRetries, err = soap.MarshalUi4(NewDelayBetweenRetries); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "SetCallRetryInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewISPPhoneNumber: -// -// * NewISPInfo: -// -// * NewLinkType: allowed values: PPP_Dialup -func (client *WANPOTSLinkConfig1) GetISPInfo() (NewISPPhoneNumber string, NewISPInfo string, NewLinkType string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewISPPhoneNumber string - - NewISPInfo string - - NewLinkType string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetISPInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewISPPhoneNumber, err = soap.UnmarshalString(response.NewISPPhoneNumber); err != nil { - return - } - if NewISPInfo, err = soap.UnmarshalString(response.NewISPInfo); err != nil { - return - } - if NewLinkType, err = soap.UnmarshalString(response.NewLinkType); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewNumberOfRetries: -// -// * NewDelayBetweenRetries: -func (client *WANPOTSLinkConfig1) GetCallRetryInfo() (NewNumberOfRetries uint32, NewDelayBetweenRetries uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewNumberOfRetries string - - NewDelayBetweenRetries string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetCallRetryInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewNumberOfRetries, err = soap.UnmarshalUi4(response.NewNumberOfRetries); err != nil { - return - } - if NewDelayBetweenRetries, err = soap.UnmarshalUi4(response.NewDelayBetweenRetries); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewFclass: -func (client *WANPOTSLinkConfig1) GetFclass() (NewFclass string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewFclass string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetFclass", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewFclass, err = soap.UnmarshalString(response.NewFclass); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataModulationSupported: -func (client *WANPOTSLinkConfig1) GetDataModulationSupported() (NewDataModulationSupported string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataModulationSupported string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataModulationSupported", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataModulationSupported, err = soap.UnmarshalString(response.NewDataModulationSupported); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataProtocol: -func (client *WANPOTSLinkConfig1) GetDataProtocol() (NewDataProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataProtocol, err = soap.UnmarshalString(response.NewDataProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewDataCompression: -func (client *WANPOTSLinkConfig1) GetDataCompression() (NewDataCompression string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewDataCompression string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetDataCompression", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewDataCompression, err = soap.UnmarshalString(response.NewDataCompression); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPlusVTRCommandSupported: -func (client *WANPOTSLinkConfig1) GetPlusVTRCommandSupported() (NewPlusVTRCommandSupported bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPlusVTRCommandSupported string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPOTSLinkConfig_1, "GetPlusVTRCommandSupported", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPlusVTRCommandSupported, err = soap.UnmarshalBoolean(response.NewPlusVTRCommandSupported); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// WANPPPConnection1 is a client for UPnP SOAP service with URN "urn:schemas-upnp-org:service:WANPPPConnection:1". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type WANPPPConnection1 struct { - goupnp.ServiceClient -} - -// NewWANPPPConnection1Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func NewWANPPPConnection1Clients() (clients []*WANPPPConnection1, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients(URN_WANPPPConnection_1); err != nil { - return - } - clients = make([]*WANPPPConnection1, len(genericClients)) - for i := range genericClients { - clients[i] = &WANPPPConnection1{genericClients[i]} - } - return -} - -// Arguments: -// -// * NewConnectionType: -// -// -func (client *WANPPPConnection1) SetConnectionType(NewConnectionType string) (err error) { - // Request structure. - request := &struct { - NewConnectionType string - }{} - // BEGIN Marshal arguments into request. - - if request.NewConnectionType, err = soap.MarshalString(NewConnectionType); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetConnectionType", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionType: -// -// * NewPossibleConnectionTypes: allowed values: Unconfigured, IP_Routed, DHCP_Spoofed, PPPoE_Bridged, PPTP_Relay, L2TP_Relay, PPPoE_Relay -func (client *WANPPPConnection1) GetConnectionTypeInfo() (NewConnectionType string, NewPossibleConnectionTypes string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionType string - - NewPossibleConnectionTypes string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetConnectionTypeInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionType, err = soap.UnmarshalString(response.NewConnectionType); err != nil { - return - } - if NewPossibleConnectionTypes, err = soap.UnmarshalString(response.NewPossibleConnectionTypes); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewUserName: -// -// * NewPassword: -// -// -func (client *WANPPPConnection1) ConfigureConnection(NewUserName string, NewPassword string) (err error) { - // Request structure. - request := &struct { - NewUserName string - - NewPassword string - }{} - // BEGIN Marshal arguments into request. - - if request.NewUserName, err = soap.MarshalString(NewUserName); err != nil { - return - } - if request.NewPassword, err = soap.MarshalString(NewPassword); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ConfigureConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) RequestConnection() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestConnection", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) RequestTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "RequestTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// -func (client *WANPPPConnection1) ForceTermination() (err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "ForceTermination", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewAutoDisconnectTime: -// -// -func (client *WANPPPConnection1) SetAutoDisconnectTime(NewAutoDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewAutoDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewAutoDisconnectTime, err = soap.MarshalUi4(NewAutoDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewIdleDisconnectTime: -// -// -func (client *WANPPPConnection1) SetIdleDisconnectTime(NewIdleDisconnectTime uint32) (err error) { - // Request structure. - request := &struct { - NewIdleDisconnectTime string - }{} - // BEGIN Marshal arguments into request. - - if request.NewIdleDisconnectTime, err = soap.MarshalUi4(NewIdleDisconnectTime); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewWarnDisconnectDelay: -// -// -func (client *WANPPPConnection1) SetWarnDisconnectDelay(NewWarnDisconnectDelay uint32) (err error) { - // Request structure. - request := &struct { - NewWarnDisconnectDelay string - }{} - // BEGIN Marshal arguments into request. - - if request.NewWarnDisconnectDelay, err = soap.MarshalUi4(NewWarnDisconnectDelay); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "SetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewConnectionStatus: allowed values: Unconfigured, Connected, Disconnected -// -// * NewLastConnectionError: allowed values: ERROR_NONE -// -// * NewUptime: -func (client *WANPPPConnection1) GetStatusInfo() (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewConnectionStatus string - - NewLastConnectionError string - - NewUptime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetStatusInfo", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewConnectionStatus, err = soap.UnmarshalString(response.NewConnectionStatus); err != nil { - return - } - if NewLastConnectionError, err = soap.UnmarshalString(response.NewLastConnectionError); err != nil { - return - } - if NewUptime, err = soap.UnmarshalUi4(response.NewUptime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUpstreamMaxBitRate: -// -// * NewDownstreamMaxBitRate: -func (client *WANPPPConnection1) GetLinkLayerMaxBitRates() (NewUpstreamMaxBitRate uint32, NewDownstreamMaxBitRate uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUpstreamMaxBitRate string - - NewDownstreamMaxBitRate string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetLinkLayerMaxBitRates", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUpstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewUpstreamMaxBitRate); err != nil { - return - } - if NewDownstreamMaxBitRate, err = soap.UnmarshalUi4(response.NewDownstreamMaxBitRate); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPEncryptionProtocol: -func (client *WANPPPConnection1) GetPPPEncryptionProtocol() (NewPPPEncryptionProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPEncryptionProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPEncryptionProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPEncryptionProtocol, err = soap.UnmarshalString(response.NewPPPEncryptionProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPCompressionProtocol: -func (client *WANPPPConnection1) GetPPPCompressionProtocol() (NewPPPCompressionProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPCompressionProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPCompressionProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPCompressionProtocol, err = soap.UnmarshalString(response.NewPPPCompressionProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPPPAuthenticationProtocol: -func (client *WANPPPConnection1) GetPPPAuthenticationProtocol() (NewPPPAuthenticationProtocol string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPPPAuthenticationProtocol string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPPPAuthenticationProtocol", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPPPAuthenticationProtocol, err = soap.UnmarshalString(response.NewPPPAuthenticationProtocol); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewUserName: -func (client *WANPPPConnection1) GetUserName() (NewUserName string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewUserName string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetUserName", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewUserName, err = soap.UnmarshalString(response.NewUserName); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewPassword: -func (client *WANPPPConnection1) GetPassword() (NewPassword string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewPassword string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetPassword", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewPassword, err = soap.UnmarshalString(response.NewPassword); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewAutoDisconnectTime: -func (client *WANPPPConnection1) GetAutoDisconnectTime() (NewAutoDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewAutoDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetAutoDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewAutoDisconnectTime, err = soap.UnmarshalUi4(response.NewAutoDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewIdleDisconnectTime: -func (client *WANPPPConnection1) GetIdleDisconnectTime() (NewIdleDisconnectTime uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewIdleDisconnectTime string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetIdleDisconnectTime", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewIdleDisconnectTime, err = soap.UnmarshalUi4(response.NewIdleDisconnectTime); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewWarnDisconnectDelay: -func (client *WANPPPConnection1) GetWarnDisconnectDelay() (NewWarnDisconnectDelay uint32, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewWarnDisconnectDelay string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetWarnDisconnectDelay", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewWarnDisconnectDelay, err = soap.UnmarshalUi4(response.NewWarnDisconnectDelay); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewRSIPAvailable: -// -// * NewNATEnabled: -func (client *WANPPPConnection1) GetNATRSIPStatus() (NewRSIPAvailable bool, NewNATEnabled bool, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRSIPAvailable string - - NewNATEnabled string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetNATRSIPStatus", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRSIPAvailable, err = soap.UnmarshalBoolean(response.NewRSIPAvailable); err != nil { - return - } - if NewNATEnabled, err = soap.UnmarshalBoolean(response.NewNATEnabled); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewPortMappingIndex: -// -// Return values: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANPPPConnection1) GetGenericPortMappingEntry(NewPortMappingIndex uint16) (NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewPortMappingIndex string - }{} - // BEGIN Marshal arguments into request. - - if request.NewPortMappingIndex, err = soap.MarshalUi2(NewPortMappingIndex); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetGenericPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewRemoteHost, err = soap.UnmarshalString(response.NewRemoteHost); err != nil { - return - } - if NewExternalPort, err = soap.UnmarshalUi2(response.NewExternalPort); err != nil { - return - } - if NewProtocol, err = soap.UnmarshalString(response.NewProtocol); err != nil { - return - } - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// Return values: -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -func (client *WANPPPConnection1) GetSpecificPortMappingEntry(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32, err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetSpecificPortMappingEntry", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewInternalPort, err = soap.UnmarshalUi2(response.NewInternalPort); err != nil { - return - } - if NewInternalClient, err = soap.UnmarshalString(response.NewInternalClient); err != nil { - return - } - if NewEnabled, err = soap.UnmarshalBoolean(response.NewEnabled); err != nil { - return - } - if NewPortMappingDescription, err = soap.UnmarshalString(response.NewPortMappingDescription); err != nil { - return - } - if NewLeaseDuration, err = soap.UnmarshalUi4(response.NewLeaseDuration); err != nil { - return - } - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// * NewInternalPort: -// -// * NewInternalClient: -// -// * NewEnabled: -// -// * NewPortMappingDescription: -// -// * NewLeaseDuration: -// -// -func (client *WANPPPConnection1) AddPortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string, NewInternalPort uint16, NewInternalClient string, NewEnabled bool, NewPortMappingDescription string, NewLeaseDuration uint32) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - - NewInternalPort string - - NewInternalClient string - - NewEnabled string - - NewPortMappingDescription string - - NewLeaseDuration string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - if request.NewInternalPort, err = soap.MarshalUi2(NewInternalPort); err != nil { - return - } - if request.NewInternalClient, err = soap.MarshalString(NewInternalClient); err != nil { - return - } - if request.NewEnabled, err = soap.MarshalBoolean(NewEnabled); err != nil { - return - } - if request.NewPortMappingDescription, err = soap.MarshalString(NewPortMappingDescription); err != nil { - return - } - if request.NewLeaseDuration, err = soap.MarshalUi4(NewLeaseDuration); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "AddPortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// Arguments: -// -// * NewRemoteHost: -// -// * NewExternalPort: -// -// * NewProtocol: allowed values: TCP, UDP -// -// -func (client *WANPPPConnection1) DeletePortMapping(NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { - // Request structure. - request := &struct { - NewRemoteHost string - - NewExternalPort string - - NewProtocol string - }{} - // BEGIN Marshal arguments into request. - - if request.NewRemoteHost, err = soap.MarshalString(NewRemoteHost); err != nil { - return - } - if request.NewExternalPort, err = soap.MarshalUi2(NewExternalPort); err != nil { - return - } - if request.NewProtocol, err = soap.MarshalString(NewProtocol); err != nil { - return - } - // END Marshal arguments into request. - - // Response structure. - response := interface{}(nil) - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "DeletePortMapping", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - // END Unmarshal arguments from response. - return -} - -// -// -// Return values: -// -// * NewExternalIPAddress: -func (client *WANPPPConnection1) GetExternalIPAddress() (NewExternalIPAddress string, err error) { - // Request structure. - request := interface{}(nil) - // BEGIN Marshal arguments into request. - - // END Marshal arguments into request. - - // Response structure. - response := &struct { - NewExternalIPAddress string - }{} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(URN_WANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. - - if NewExternalIPAddress, err = soap.UnmarshalString(response.NewExternalIPAddress); err != nil { - return - } - // END Unmarshal arguments from response. - return -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/device.go b/Godeps/_workspace/src/github.com/huin/goupnp/device.go deleted file mode 100644 index b250191eb..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/device.go +++ /dev/null @@ -1,184 +0,0 @@ -// This file contains XML structures for communicating with UPnP devices. - -package goupnp - -import ( - "encoding/xml" - "errors" - "fmt" - "net/url" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/scpd" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/soap" -) - -const ( - DeviceXMLNamespace = "urn:schemas-upnp-org:device-1-0" -) - -// RootDevice is the device description as described by section 2.3 "Device -// description" in -// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf -type RootDevice struct { - XMLName xml.Name `xml:"root"` - SpecVersion SpecVersion `xml:"specVersion"` - URLBase url.URL `xml:"-"` - URLBaseStr string `xml:"URLBase"` - Device Device `xml:"device"` -} - -// SetURLBase sets the URLBase for the RootDevice and its underlying components. -func (root *RootDevice) SetURLBase(urlBase *url.URL) { - root.URLBase = *urlBase - root.URLBaseStr = urlBase.String() - root.Device.SetURLBase(urlBase) -} - -// SpecVersion is part of a RootDevice, describes the version of the -// specification that the data adheres to. -type SpecVersion struct { - Major int32 `xml:"major"` - Minor int32 `xml:"minor"` -} - -// Device is a UPnP device. It can have child devices. -type Device struct { - DeviceType string `xml:"deviceType"` - FriendlyName string `xml:"friendlyName"` - Manufacturer string `xml:"manufacturer"` - ManufacturerURL URLField `xml:"manufacturerURL"` - ModelDescription string `xml:"modelDescription"` - ModelName string `xml:"modelName"` - ModelNumber string `xml:"modelNumber"` - ModelURL URLField `xml:"modelURL"` - SerialNumber string `xml:"serialNumber"` - UDN string `xml:"UDN"` - UPC string `xml:"UPC,omitempty"` - Icons []Icon `xml:"iconList>icon,omitempty"` - Services []Service `xml:"serviceList>service,omitempty"` - Devices []Device `xml:"deviceList>device,omitempty"` - - // Extra observed elements: - PresentationURL URLField `xml:"presentationURL"` -} - -// VisitDevices calls visitor for the device, and all its descendent devices. -func (device *Device) VisitDevices(visitor func(*Device)) { - visitor(device) - for i := range device.Devices { - device.Devices[i].VisitDevices(visitor) - } -} - -// VisitServices calls visitor for all Services under the device and all its -// descendent devices. -func (device *Device) VisitServices(visitor func(*Service)) { - device.VisitDevices(func(d *Device) { - for i := range d.Services { - visitor(&d.Services[i]) - } - }) -} - -// FindService finds all (if any) Services under the device and its descendents -// that have the given ServiceType. -func (device *Device) FindService(serviceType string) []*Service { - var services []*Service - device.VisitServices(func(s *Service) { - if s.ServiceType == serviceType { - services = append(services, s) - } - }) - return services -} - -// SetURLBase sets the URLBase for the Device and its underlying components. -func (device *Device) SetURLBase(urlBase *url.URL) { - device.ManufacturerURL.SetURLBase(urlBase) - device.ModelURL.SetURLBase(urlBase) - device.PresentationURL.SetURLBase(urlBase) - for i := range device.Icons { - device.Icons[i].SetURLBase(urlBase) - } - for i := range device.Services { - device.Services[i].SetURLBase(urlBase) - } - for i := range device.Devices { - device.Devices[i].SetURLBase(urlBase) - } -} - -func (device *Device) String() string { - return fmt.Sprintf("Device ID %s : %s (%s)", device.UDN, device.DeviceType, device.FriendlyName) -} - -// Icon is a representative image that a device might include in its -// description. -type Icon struct { - Mimetype string `xml:"mimetype"` - Width int32 `xml:"width"` - Height int32 `xml:"height"` - Depth int32 `xml:"depth"` - URL URLField `xml:"url"` -} - -// SetURLBase sets the URLBase for the Icon. -func (icon *Icon) SetURLBase(url *url.URL) { - icon.URL.SetURLBase(url) -} - -// Service is a service provided by a UPnP Device. -type Service struct { - ServiceType string `xml:"serviceType"` - ServiceId string `xml:"serviceId"` - SCPDURL URLField `xml:"SCPDURL"` - ControlURL URLField `xml:"controlURL"` - EventSubURL URLField `xml:"eventSubURL"` -} - -// SetURLBase sets the URLBase for the Service. -func (srv *Service) SetURLBase(urlBase *url.URL) { - srv.SCPDURL.SetURLBase(urlBase) - srv.ControlURL.SetURLBase(urlBase) - srv.EventSubURL.SetURLBase(urlBase) -} - -func (srv *Service) String() string { - return fmt.Sprintf("Service ID %s : %s", srv.ServiceId, srv.ServiceType) -} - -// RequestSCDP requests the SCPD (soap actions and state variables description) -// for the service. -func (srv *Service) RequestSCDP() (*scpd.SCPD, error) { - if !srv.SCPDURL.Ok { - return nil, errors.New("bad/missing SCPD URL, or no URLBase has been set") - } - s := new(scpd.SCPD) - if err := requestXml(srv.SCPDURL.URL.String(), scpd.SCPDXMLNamespace, s); err != nil { - return nil, err - } - return s, nil -} - -func (srv *Service) NewSOAPClient() *soap.SOAPClient { - return soap.NewSOAPClient(srv.ControlURL.URL) -} - -// URLField is a URL that is part of a device description. -type URLField struct { - URL url.URL `xml:"-"` - Ok bool `xml:"-"` - Str string `xml:",chardata"` -} - -func (uf *URLField) SetURLBase(urlBase *url.URL) { - refUrl, err := url.Parse(uf.Str) - if err != nil { - uf.URL = url.URL{} - uf.Ok = false - return - } - - uf.URL = *urlBase.ResolveReference(refUrl) - uf.Ok = true -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go b/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go deleted file mode 100644 index df7420226..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/example/example.go +++ /dev/null @@ -1,6 +0,0 @@ -// Serves as examples of using the goupnp library. -// -// To run examples and see the output for your local network, run the following -// command (specifically including the -v flag): -// go test -v github.com/huin/goupnp/example -package example diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go deleted file mode 100644 index df39882ab..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/example/example_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package example_test - -import ( - "fmt" - "os" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/dcps/internetgateway1" -) - -// Use discovered WANPPPConnection1 services to find external IP addresses. -func Example_WANPPPConnection1_GetExternalIPAddress() { - clients, errors, err := internetgateway1.NewWANPPPConnection1Clients() - extIPClients := make([]GetExternalIPAddresser, len(clients)) - for i, client := range clients { - extIPClients[i] = client - } - DisplayExternalIPResults(extIPClients, errors, err) - // Output: -} - -// Use discovered WANIPConnection services to find external IP addresses. -func Example_WANIPConnection_GetExternalIPAddress() { - clients, errors, err := internetgateway1.NewWANIPConnection1Clients() - extIPClients := make([]GetExternalIPAddresser, len(clients)) - for i, client := range clients { - extIPClients[i] = client - } - DisplayExternalIPResults(extIPClients, errors, err) - // Output: -} - -type GetExternalIPAddresser interface { - GetExternalIPAddress() (NewExternalIPAddress string, err error) - GetServiceClient() *goupnp.ServiceClient -} - -func DisplayExternalIPResults(clients []GetExternalIPAddresser, errors []error, err error) { - if err != nil { - fmt.Fprintln(os.Stderr, "Error discovering service with UPnP: ", err) - return - } - - if len(errors) > 0 { - fmt.Fprintf(os.Stderr, "Error discovering %d services:\n", len(errors)) - for _, err := range errors { - fmt.Println(" ", err) - } - } - - fmt.Fprintf(os.Stderr, "Successfully discovered %d services:\n", len(clients)) - for _, client := range clients { - device := &client.GetServiceClient().RootDevice.Device - - fmt.Fprintln(os.Stderr, " Device:", device.FriendlyName) - if addr, err := client.GetExternalIPAddress(); err != nil { - fmt.Fprintf(os.Stderr, " Failed to get external IP address: %v\n", err) - } else { - fmt.Fprintf(os.Stderr, " External IP address: %v\n", addr) - } - } -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go b/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go deleted file mode 100644 index 7180b9586..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/gotasks/specgen_task.go +++ /dev/null @@ -1,539 +0,0 @@ -// +build gotask - -package gotasks - -import ( - "archive/zip" - "bytes" - "encoding/xml" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "regexp" - "strings" - "text/template" - - "github.com/huin/goutil/codegen" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/scpd" - "github.com/jingweno/gotask/tasking" -) - -var ( - deviceURNPrefix = "urn:schemas-upnp-org:device:" - serviceURNPrefix = "urn:schemas-upnp-org:service:" -) - -// NAME -// specgen - generates Go code from the UPnP specification files. -// -// DESCRIPTION -// The specification is available for download from: -// -// OPTIONS -// -s, --spec_filename= -// Path to the specification file, available from http://upnp.org/resources/upnpresources.zip -// -o, --out_dir= -// Path to the output directory. This is is where the DCP source files will be placed. Should normally correspond to the directory for github.com/huin/goupnp/dcps -// --nogofmt -// Disable passing the output through gofmt. Do this if debugging code output problems and needing to see the generated code prior to being passed through gofmt. -func TaskSpecgen(t *tasking.T) { - specFilename := t.Flags.String("spec-filename") - if specFilename == "" { - specFilename = t.Flags.String("s") - } - if specFilename == "" { - t.Fatal("--spec_filename is required") - } - outDir := t.Flags.String("out-dir") - if outDir == "" { - outDir = t.Flags.String("o") - } - if outDir == "" { - log.Fatal("--out_dir is required") - } - useGofmt := !t.Flags.Bool("nogofmt") - - specArchive, err := openZipfile(specFilename) - if err != nil { - t.Fatalf("Error opening spec file: %v", err) - } - defer specArchive.Close() - - dcpCol := newDcpsCollection() - for _, f := range globFiles("standardizeddcps/*/*.zip", specArchive.Reader) { - dirName := strings.TrimPrefix(f.Name, "standardizeddcps/") - slashIndex := strings.Index(dirName, "/") - if slashIndex == -1 { - // Should not happen. - t.Logf("Could not find / in %q", dirName) - return - } - dirName = dirName[:slashIndex] - - dcp := dcpCol.dcpForDir(dirName) - if dcp == nil { - t.Logf("No alias defined for directory %q: skipping %s\n", dirName, f.Name) - continue - } else { - t.Logf("Alias found for directory %q: processing %s\n", dirName, f.Name) - } - - dcp.processZipFile(f) - } - - for _, dcp := range dcpCol.dcpByAlias { - if err := dcp.writePackage(outDir, useGofmt); err != nil { - log.Printf("Error writing package %q: %v", dcp.Metadata.Name, err) - } - } -} - -// DCP contains extra metadata to use when generating DCP source files. -type DCPMetadata struct { - Name string // What to name the Go DCP package. - OfficialName string // Official name for the DCP. - DocURL string // Optional - URL for futher documentation about the DCP. -} - -var dcpMetadataByDir = map[string]DCPMetadata{ - "Internet Gateway_1": { - Name: "internetgateway1", - OfficialName: "Internet Gateway Device v1", - DocURL: "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf", - }, - "Internet Gateway_2": { - Name: "internetgateway2", - OfficialName: "Internet Gateway Device v2", - DocURL: "http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf", - }, -} - -type dcpCollection struct { - dcpByAlias map[string]*DCP -} - -func newDcpsCollection() *dcpCollection { - c := &dcpCollection{ - dcpByAlias: make(map[string]*DCP), - } - for _, metadata := range dcpMetadataByDir { - c.dcpByAlias[metadata.Name] = newDCP(metadata) - } - return c -} - -func (c *dcpCollection) dcpForDir(dirName string) *DCP { - metadata, ok := dcpMetadataByDir[dirName] - if !ok { - return nil - } - return c.dcpByAlias[metadata.Name] -} - -// DCP collects together information about a UPnP Device Control Protocol. -type DCP struct { - Metadata DCPMetadata - DeviceTypes map[string]*URNParts - ServiceTypes map[string]*URNParts - Services []SCPDWithURN -} - -func newDCP(metadata DCPMetadata) *DCP { - return &DCP{ - Metadata: metadata, - DeviceTypes: make(map[string]*URNParts), - ServiceTypes: make(map[string]*URNParts), - } -} - -func (dcp *DCP) processZipFile(file *zip.File) { - archive, err := openChildZip(file) - if err != nil { - log.Println("Error reading child zip file:", err) - return - } - for _, deviceFile := range globFiles("*/device/*.xml", archive) { - dcp.processDeviceFile(deviceFile) - } - for _, scpdFile := range globFiles("*/service/*.xml", archive) { - dcp.processSCPDFile(scpdFile) - } -} - -func (dcp *DCP) processDeviceFile(file *zip.File) { - var device goupnp.Device - if err := unmarshalXmlFile(file, &device); err != nil { - log.Printf("Error decoding device XML from file %q: %v", file.Name, err) - return - } - device.VisitDevices(func(d *goupnp.Device) { - t := strings.TrimSpace(d.DeviceType) - if t != "" { - u, err := extractURNParts(t, deviceURNPrefix) - if err != nil { - log.Println(err) - return - } - dcp.DeviceTypes[t] = u - } - }) - device.VisitServices(func(s *goupnp.Service) { - u, err := extractURNParts(s.ServiceType, serviceURNPrefix) - if err != nil { - log.Println(err) - return - } - dcp.ServiceTypes[s.ServiceType] = u - }) -} - -func (dcp *DCP) writePackage(outDir string, useGofmt bool) error { - packageDirname := filepath.Join(outDir, dcp.Metadata.Name) - err := os.MkdirAll(packageDirname, os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - packageFilename := filepath.Join(packageDirname, dcp.Metadata.Name+".go") - packageFile, err := os.Create(packageFilename) - if err != nil { - return err - } - var output io.WriteCloser = packageFile - if useGofmt { - if output, err = codegen.NewGofmtWriteCloser(output); err != nil { - packageFile.Close() - return err - } - } - if err = packageTmpl.Execute(output, dcp); err != nil { - output.Close() - return err - } - return output.Close() -} - -func (dcp *DCP) processSCPDFile(file *zip.File) { - scpd := new(scpd.SCPD) - if err := unmarshalXmlFile(file, scpd); err != nil { - log.Printf("Error decoding SCPD XML from file %q: %v", file.Name, err) - return - } - scpd.Clean() - urnParts, err := urnPartsFromSCPDFilename(file.Name) - if err != nil { - log.Printf("Could not recognize SCPD filename %q: %v", file.Name, err) - return - } - dcp.Services = append(dcp.Services, SCPDWithURN{ - URNParts: urnParts, - SCPD: scpd, - }) -} - -type SCPDWithURN struct { - *URNParts - SCPD *scpd.SCPD -} - -func (s *SCPDWithURN) WrapArgument(arg scpd.Argument) (*argumentWrapper, error) { - relVar := s.SCPD.GetStateVariable(arg.RelatedStateVariable) - if relVar == nil { - return nil, fmt.Errorf("no such state variable: %q, for argument %q", arg.RelatedStateVariable, arg.Name) - } - cnv, ok := typeConvs[relVar.DataType.Name] - if !ok { - return nil, fmt.Errorf("unknown data type: %q, for state variable %q, for argument %q", relVar.DataType.Type, arg.RelatedStateVariable, arg.Name) - } - return &argumentWrapper{ - Argument: arg, - relVar: relVar, - conv: cnv, - }, nil -} - -type argumentWrapper struct { - scpd.Argument - relVar *scpd.StateVariable - conv conv -} - -func (arg *argumentWrapper) AsParameter() string { - return fmt.Sprintf("%s %s", arg.Name, arg.conv.ExtType) -} - -func (arg *argumentWrapper) Document() string { - relVar := arg.relVar - if rng := relVar.AllowedValueRange; rng != nil { - var parts []string - if rng.Minimum != "" { - parts = append(parts, fmt.Sprintf("minimum=%s", rng.Minimum)) - } - if rng.Maximum != "" { - parts = append(parts, fmt.Sprintf("maximum=%s", rng.Maximum)) - } - if rng.Step != "" { - parts = append(parts, fmt.Sprintf("step=%s", rng.Step)) - } - return "allowed value range: " + strings.Join(parts, ", ") - } - if len(relVar.AllowedValues) != 0 { - return "allowed values: " + strings.Join(relVar.AllowedValues, ", ") - } - return "" -} - -func (arg *argumentWrapper) Marshal() string { - return fmt.Sprintf("soap.Marshal%s(%s)", arg.conv.FuncSuffix, arg.Name) -} - -func (arg *argumentWrapper) Unmarshal(objVar string) string { - return fmt.Sprintf("soap.Unmarshal%s(%s.%s)", arg.conv.FuncSuffix, objVar, arg.Name) -} - -type conv struct { - FuncSuffix string - ExtType string -} - -// typeConvs maps from a SOAP type (e.g "fixed.14.4") to the function name -// suffix inside the soap module (e.g "Fixed14_4") and the Go type. -var typeConvs = map[string]conv{ - "ui1": conv{"Ui1", "uint8"}, - "ui2": conv{"Ui2", "uint16"}, - "ui4": conv{"Ui4", "uint32"}, - "i1": conv{"I1", "int8"}, - "i2": conv{"I2", "int16"}, - "i4": conv{"I4", "int32"}, - "int": conv{"Int", "int64"}, - "r4": conv{"R4", "float32"}, - "r8": conv{"R8", "float64"}, - "number": conv{"R8", "float64"}, // Alias for r8. - "fixed.14.4": conv{"Fixed14_4", "float64"}, - "float": conv{"R8", "float64"}, - "char": conv{"Char", "rune"}, - "string": conv{"String", "string"}, - "date": conv{"Date", "time.Time"}, - "dateTime": conv{"DateTime", "time.Time"}, - "dateTime.tz": conv{"DateTimeTz", "time.Time"}, - "time": conv{"TimeOfDay", "soap.TimeOfDay"}, - "time.tz": conv{"TimeOfDayTz", "soap.TimeOfDay"}, - "boolean": conv{"Boolean", "bool"}, - "bin.base64": conv{"BinBase64", "[]byte"}, - "bin.hex": conv{"BinHex", "[]byte"}, -} - -type closeableZipReader struct { - io.Closer - *zip.Reader -} - -func openZipfile(filename string) (*closeableZipReader, error) { - file, err := os.Open(filename) - if err != nil { - return nil, err - } - fi, err := file.Stat() - if err != nil { - return nil, err - } - archive, err := zip.NewReader(file, fi.Size()) - if err != nil { - return nil, err - } - return &closeableZipReader{ - Closer: file, - Reader: archive, - }, nil -} - -// openChildZip opens a zip file within another zip file. -func openChildZip(file *zip.File) (*zip.Reader, error) { - zipFile, err := file.Open() - if err != nil { - return nil, err - } - defer zipFile.Close() - - zipBytes, err := ioutil.ReadAll(zipFile) - if err != nil { - return nil, err - } - - return zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes))) -} - -func globFiles(pattern string, archive *zip.Reader) []*zip.File { - var files []*zip.File - for _, f := range archive.File { - if matched, err := path.Match(pattern, f.Name); err != nil { - // This shouldn't happen - all patterns are hard-coded, errors in them - // are a programming error. - panic(err) - } else if matched { - files = append(files, f) - } - } - return files -} - -func unmarshalXmlFile(file *zip.File, data interface{}) error { - r, err := file.Open() - if err != nil { - return err - } - decoder := xml.NewDecoder(r) - r.Close() - return decoder.Decode(data) -} - -type URNParts struct { - URN string - Name string - Version string -} - -func (u *URNParts) Const() string { - return fmt.Sprintf("URN_%s_%s", u.Name, u.Version) -} - -// extractURNParts extracts the name and version from a URN string. -func extractURNParts(urn, expectedPrefix string) (*URNParts, error) { - if !strings.HasPrefix(urn, expectedPrefix) { - return nil, fmt.Errorf("%q does not have expected prefix %q", urn, expectedPrefix) - } - parts := strings.SplitN(strings.TrimPrefix(urn, expectedPrefix), ":", 2) - if len(parts) != 2 { - return nil, fmt.Errorf("%q does not have a name and version", urn) - } - name, version := parts[0], parts[1] - return &URNParts{urn, name, version}, nil -} - -var scpdFilenameRe = regexp.MustCompile( - `.*/([a-zA-Z0-9]+)([0-9]+)\.xml`) - -func urnPartsFromSCPDFilename(filename string) (*URNParts, error) { - parts := scpdFilenameRe.FindStringSubmatch(filename) - if len(parts) != 3 { - return nil, fmt.Errorf("SCPD filename %q does not have expected number of parts", filename) - } - name, version := parts[1], parts[2] - return &URNParts{ - URN: serviceURNPrefix + name + ":" + version, - Name: name, - Version: version, - }, nil -} - -var packageTmpl = template.Must(template.New("package").Parse(`{{$name := .Metadata.Name}} -// Client for UPnP Device Control Protocol {{.Metadata.OfficialName}}. -// {{if .Metadata.DocURL}} -// This DCP is documented in detail at: {{.Metadata.DocURL}}{{end}} -// -// Typically, use one of the New* functions to discover services on the local -// network. -package {{$name}} - -// Generated file - do not edit by hand. See README.md - - -import ( - "time" - - "github.com/huin/goupnp" - "github.com/huin/goupnp/soap" -) - -// Hack to avoid Go complaining if time isn't used. -var _ time.Time - -// Device URNs: -const ({{range .DeviceTypes}} - {{.Const}} = "{{.URN}}"{{end}} -) - -// Service URNs: -const ({{range .ServiceTypes}} - {{.Const}} = "{{.URN}}"{{end}} -) - -{{range .Services}} -{{$srv := .}} -{{$srvIdent := printf "%s%s" .Name .Version}} - -// {{$srvIdent}} is a client for UPnP SOAP service with URN "{{.URN}}". See -// goupnp.ServiceClient, which contains RootDevice and Service attributes which -// are provided for informational value. -type {{$srvIdent}} struct { - goupnp.ServiceClient -} - -// New{{$srvIdent}}Clients discovers instances of the service on the network, -// and returns clients to any that are found. errors will contain an error for -// any devices that replied but which could not be queried, and err will be set -// if the discovery process failed outright. -// -// This is a typical entry calling point into this package. -func New{{$srvIdent}}Clients() (clients []*{{$srvIdent}}, errors []error, err error) { - var genericClients []goupnp.ServiceClient - if genericClients, errors, err = goupnp.NewServiceClients({{$srv.Const}}); err != nil { - return - } - clients = make([]*{{$srvIdent}}, len(genericClients)) - for i := range genericClients { - clients[i] = &{{$srvIdent}}{genericClients[i]} - } - return -} - -{{range .SCPD.Actions}}{{/* loops over *SCPDWithURN values */}} - -{{$inargs := .InputArguments}}{{$outargs := .OutputArguments}} -// {{if $inargs}}Arguments:{{range $inargs}}{{$argWrap := $srv.WrapArgument .}} -// -// * {{.Name}}: {{$argWrap.Document}}{{end}}{{end}} -// -// {{if $outargs}}Return values:{{range $outargs}}{{$argWrap := $srv.WrapArgument .}} -// -// * {{.Name}}: {{$argWrap.Document}}{{end}}{{end}} -func (client *{{$srvIdent}}) {{.Name}}({{range $inargs}}{{/* -*/}}{{$argWrap := $srv.WrapArgument .}}{{$argWrap.AsParameter}}, {{end}}{{/* -*/}}) ({{range $outargs}}{{/* -*/}}{{$argWrap := $srv.WrapArgument .}}{{$argWrap.AsParameter}}, {{end}} err error) { - // Request structure. - request := {{if $inargs}}&{{template "argstruct" $inargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}} - // BEGIN Marshal arguments into request. -{{range $inargs}}{{$argWrap := $srv.WrapArgument .}} - if request.{{.Name}}, err = {{$argWrap.Marshal}}; err != nil { - return - }{{end}} - // END Marshal arguments into request. - - // Response structure. - response := {{if $outargs}}&{{template "argstruct" $outargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}} - - // Perform the SOAP call. - if err = client.SOAPClient.PerformAction({{$srv.URNParts.Const}}, "{{.Name}}", request, response); err != nil { - return - } - - // BEGIN Unmarshal arguments from response. -{{range $outargs}}{{$argWrap := $srv.WrapArgument .}} - if {{.Name}}, err = {{$argWrap.Unmarshal "response"}}; err != nil { - return - }{{end}} - // END Unmarshal arguments from response. - return -} -{{end}}{{/* range .SCPD.Actions */}} -{{end}}{{/* range .Services */}} - -{{define "argstruct"}}struct {{"{"}}{{range .}} -{{.Name}} string -{{end}}{{"}"}}{{end}} -`)) diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go b/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go deleted file mode 100644 index 0d4845a69..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/goupnp.go +++ /dev/null @@ -1,109 +0,0 @@ -// goupnp is an implementation of a client for various UPnP services. -// -// For most uses, it is recommended to use the code-generated packages under -// github.com/huin/goupnp/dcps. Example use is shown at -// http://godoc.org/github.com/huin/goupnp/example -// -// A commonly used client is internetgateway1.WANPPPConnection1: -// http://godoc.org/github.com/huin/goupnp/dcps/internetgateway1#WANPPPConnection1 -// -// Currently only a couple of schemas have code generated for them from the -// UPnP example XML specifications. Not all methods will work on these clients, -// because the generated stubs contain the full set of specified methods from -// the XML specifications, and the discovered services will likely support a -// subset of those methods. -package goupnp - -import ( - "encoding/xml" - "fmt" - "net/http" - "net/url" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/httpu" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/ssdp" -) - -// ContextError is an error that wraps an error with some context information. -type ContextError struct { - Context string - Err error -} - -func (err ContextError) Error() string { - return fmt.Sprintf("%s: %v", err.Context, err.Err) -} - -// MaybeRootDevice contains either a RootDevice or an error. -type MaybeRootDevice struct { - Root *RootDevice - Err error -} - -// DiscoverDevices attempts to find targets of the given type. This is -// typically the entry-point for this package. searchTarget is typically a URN -// in the form "urn:schemas-upnp-org:device:..." or -// "urn:schemas-upnp-org:service:...". A single error is returned for errors -// while attempting to send the query. An error or RootDevice is returned for -// each discovered RootDevice. -func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) { - httpu, err := httpu.NewHTTPUClient() - if err != nil { - return nil, err - } - defer httpu.Close() - responses, err := ssdp.SSDPRawSearch(httpu, string(searchTarget), 2, 3) - if err != nil { - return nil, err - } - - results := make([]MaybeRootDevice, len(responses)) - for i, response := range responses { - maybe := &results[i] - loc, err := response.Location() - if err != nil { - - maybe.Err = ContextError{"unexpected bad location from search", err} - continue - } - locStr := loc.String() - root := new(RootDevice) - if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil { - maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err} - continue - } - var urlBaseStr string - if root.URLBaseStr != "" { - urlBaseStr = root.URLBaseStr - } else { - urlBaseStr = locStr - } - urlBase, err := url.Parse(urlBaseStr) - if err != nil { - maybe.Err = ContextError{fmt.Sprintf("error parsing location URL %q", locStr), err} - continue - } - root.SetURLBase(urlBase) - maybe.Root = root - } - - return results, nil -} - -func requestXml(url string, defaultSpace string, doc interface{}) error { - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("goupnp: got response status %s from %q", - resp.Status, url) - } - - decoder := xml.NewDecoder(resp.Body) - decoder.DefaultSpace = defaultSpace - - return decoder.Decode(doc) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go deleted file mode 100644 index 862c3def4..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go +++ /dev/null @@ -1,117 +0,0 @@ -package httpu - -import ( - "bufio" - "bytes" - "fmt" - "log" - "net" - "net/http" - "sync" - "time" -) - -// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical -// function is for HTTPMU, and particularly SSDP. -type HTTPUClient struct { - connLock sync.Mutex // Protects use of conn. - conn net.PacketConn -} - -// NewHTTPUClient creates a new HTTPUClient, opening up a new UDP socket for the -// purpose. -func NewHTTPUClient() (*HTTPUClient, error) { - conn, err := net.ListenPacket("udp", ":0") - if err != nil { - return nil, err - } - return &HTTPUClient{conn: conn}, nil -} - -// Close shuts down the client. The client will no longer be useful following -// this. -func (httpu *HTTPUClient) Close() error { - httpu.connLock.Lock() - defer httpu.connLock.Unlock() - return httpu.conn.Close() -} - -// Do performs a request. The timeout is how long to wait for before returning -// the responses that were received. An error is only returned for failing to -// send the request. Failures in receipt simply do not add to the resulting -// responses. -// -// Note that at present only one concurrent connection will happen per -// HTTPUClient. -func (httpu *HTTPUClient) Do(req *http.Request, timeout time.Duration, numSends int) ([]*http.Response, error) { - httpu.connLock.Lock() - defer httpu.connLock.Unlock() - - // Create the request. This is a subset of what http.Request.Write does - // deliberately to avoid creating extra fields which may confuse some - // devices. - var requestBuf bytes.Buffer - method := req.Method - if method == "" { - method = "GET" - } - if _, err := fmt.Fprintf(&requestBuf, "%s %s HTTP/1.1\r\n", method, req.URL.RequestURI()); err != nil { - return nil, err - } - if err := req.Header.Write(&requestBuf); err != nil { - return nil, err - } - if _, err := requestBuf.Write([]byte{'\r', '\n'}); err != nil { - return nil, err - } - - destAddr, err := net.ResolveUDPAddr("udp", req.Host) - if err != nil { - return nil, err - } - if err = httpu.conn.SetDeadline(time.Now().Add(timeout)); err != nil { - return nil, err - } - - // Send request. - for i := 0; i < numSends; i++ { - if n, err := httpu.conn.WriteTo(requestBuf.Bytes(), destAddr); err != nil { - return nil, err - } else if n < len(requestBuf.Bytes()) { - return nil, fmt.Errorf("httpu: wrote %d bytes rather than full %d in request", - n, len(requestBuf.Bytes())) - } - time.Sleep(5 * time.Millisecond) - } - - // Await responses until timeout. - var responses []*http.Response - responseBytes := make([]byte, 2048) - for { - // 2048 bytes should be sufficient for most networks. - n, _, err := httpu.conn.ReadFrom(responseBytes) - if err != nil { - if err, ok := err.(net.Error); ok { - if err.Timeout() { - break - } - if err.Temporary() { - // Sleep in case this is a persistent error to avoid pegging CPU until deadline. - time.Sleep(10 * time.Millisecond) - continue - } - } - return nil, err - } - - // Parse response. - response, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(responseBytes[:n])), req) - if err != nil { - log.Print("httpu: error while parsing response: %v", err) - continue - } - - responses = append(responses, response) - } - return responses, err -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go deleted file mode 100644 index 9f67af85b..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/serve.go +++ /dev/null @@ -1,108 +0,0 @@ -package httpu - -import ( - "bufio" - "bytes" - "log" - "net" - "net/http" - "regexp" -) - -const ( - DefaultMaxMessageBytes = 2048 -) - -var ( - trailingWhitespaceRx = regexp.MustCompile(" +\r\n") - crlf = []byte("\r\n") -) - -// Handler is the interface by which received HTTPU messages are passed to -// handling code. -type Handler interface { - // ServeMessage is called for each HTTPU message received. peerAddr contains - // the address that the message was received from. - ServeMessage(r *http.Request) -} - -// HandlerFunc is a function-to-Handler adapter. -type HandlerFunc func(r *http.Request) - -func (f HandlerFunc) ServeMessage(r *http.Request) { - f(r) -} - -// A Server defines parameters for running an HTTPU server. -type Server struct { - Addr string // UDP address to listen on - Multicast bool // Should listen for multicast? - Interface *net.Interface // Network interface to listen on for multicast, nil for default multicast interface - Handler Handler // handler to invoke - MaxMessageBytes int // maximum number of bytes to read from a packet, DefaultMaxMessageBytes if 0 -} - -// ListenAndServe listens on the UDP network address srv.Addr. If srv.Multicast -// is true, then a multicast UDP listener will be used on srv.Interface (or -// default interface if nil). -func (srv *Server) ListenAndServe() error { - var err error - - var addr *net.UDPAddr - if addr, err = net.ResolveUDPAddr("udp", srv.Addr); err != nil { - log.Fatal(err) - } - - var conn net.PacketConn - if srv.Multicast { - if conn, err = net.ListenMulticastUDP("udp", srv.Interface, addr); err != nil { - return err - } - } else { - if conn, err = net.ListenUDP("udp", addr); err != nil { - return err - } - } - - return srv.Serve(conn) -} - -// Serve messages received on the given packet listener to the srv.Handler. -func (srv *Server) Serve(l net.PacketConn) error { - maxMessageBytes := DefaultMaxMessageBytes - if srv.MaxMessageBytes != 0 { - maxMessageBytes = srv.MaxMessageBytes - } - for { - buf := make([]byte, maxMessageBytes) - n, peerAddr, err := l.ReadFrom(buf) - if err != nil { - return err - } - buf = buf[:n] - - go func(buf []byte, peerAddr net.Addr) { - // At least one router's UPnP implementation has added a trailing space - // after "HTTP/1.1" - trim it. - buf = trailingWhitespaceRx.ReplaceAllLiteral(buf, crlf) - - req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(buf))) - if err != nil { - log.Printf("httpu: Failed to parse request: %v", err) - return - } - req.RemoteAddr = peerAddr.String() - srv.Handler.ServeMessage(req) - // No need to call req.Body.Close - underlying reader is bytes.Buffer. - }(buf, peerAddr) - } -} - -// Serve messages received on the given packet listener to the given handler. -func Serve(l net.PacketConn, handler Handler) error { - srv := Server{ - Handler: handler, - MaxMessageBytes: DefaultMaxMessageBytes, - } - return srv.Serve(l) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go b/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go deleted file mode 100644 index c9d2e69e8..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/scpd/scpd.go +++ /dev/null @@ -1,167 +0,0 @@ -package scpd - -import ( - "encoding/xml" - "strings" -) - -const ( - SCPDXMLNamespace = "urn:schemas-upnp-org:service-1-0" -) - -func cleanWhitespace(s *string) { - *s = strings.TrimSpace(*s) -} - -// SCPD is the service description as described by section 2.5 "Service -// description" in -// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf -type SCPD struct { - XMLName xml.Name `xml:"scpd"` - ConfigId string `xml:"configId,attr"` - SpecVersion SpecVersion `xml:"specVersion"` - Actions []Action `xml:"actionList>action"` - StateVariables []StateVariable `xml:"serviceStateTable>stateVariable"` -} - -// Clean attempts to remove stray whitespace etc. in the structure. It seems -// unfortunately common for stray whitespace to be present in SCPD documents, -// this method attempts to make it easy to clean them out. -func (scpd *SCPD) Clean() { - cleanWhitespace(&scpd.ConfigId) - for i := range scpd.Actions { - scpd.Actions[i].clean() - } - for i := range scpd.StateVariables { - scpd.StateVariables[i].clean() - } -} - -func (scpd *SCPD) GetStateVariable(variable string) *StateVariable { - for i := range scpd.StateVariables { - v := &scpd.StateVariables[i] - if v.Name == variable { - return v - } - } - return nil -} - -func (scpd *SCPD) GetAction(action string) *Action { - for i := range scpd.Actions { - a := &scpd.Actions[i] - if a.Name == action { - return a - } - } - return nil -} - -// SpecVersion is part of a SCPD document, describes the version of the -// specification that the data adheres to. -type SpecVersion struct { - Major int32 `xml:"major"` - Minor int32 `xml:"minor"` -} - -type Action struct { - Name string `xml:"name"` - Arguments []Argument `xml:"argumentList>argument"` -} - -func (action *Action) clean() { - cleanWhitespace(&action.Name) - for i := range action.Arguments { - action.Arguments[i].clean() - } -} - -func (action *Action) InputArguments() []*Argument { - var result []*Argument - for i := range action.Arguments { - arg := &action.Arguments[i] - if arg.IsInput() { - result = append(result, arg) - } - } - return result -} - -func (action *Action) OutputArguments() []*Argument { - var result []*Argument - for i := range action.Arguments { - arg := &action.Arguments[i] - if arg.IsOutput() { - result = append(result, arg) - } - } - return result -} - -type Argument struct { - Name string `xml:"name"` - Direction string `xml:"direction"` // in|out - RelatedStateVariable string `xml:"relatedStateVariable"` // ? - Retval string `xml:"retval"` // ? -} - -func (arg *Argument) clean() { - cleanWhitespace(&arg.Name) - cleanWhitespace(&arg.Direction) - cleanWhitespace(&arg.RelatedStateVariable) - cleanWhitespace(&arg.Retval) -} - -func (arg *Argument) IsInput() bool { - return arg.Direction == "in" -} - -func (arg *Argument) IsOutput() bool { - return arg.Direction == "out" -} - -type StateVariable struct { - Name string `xml:"name"` - SendEvents string `xml:"sendEvents,attr"` // yes|no - Multicast string `xml:"multicast,attr"` // yes|no - DataType DataType `xml:"dataType"` - DefaultValue string `xml:"defaultValue"` - AllowedValueRange *AllowedValueRange `xml:"allowedValueRange"` - AllowedValues []string `xml:"allowedValueList>allowedValue"` -} - -func (v *StateVariable) clean() { - cleanWhitespace(&v.Name) - cleanWhitespace(&v.SendEvents) - cleanWhitespace(&v.Multicast) - v.DataType.clean() - cleanWhitespace(&v.DefaultValue) - if v.AllowedValueRange != nil { - v.AllowedValueRange.clean() - } - for i := range v.AllowedValues { - cleanWhitespace(&v.AllowedValues[i]) - } -} - -type AllowedValueRange struct { - Minimum string `xml:"minimum"` - Maximum string `xml:"maximum"` - Step string `xml:"step"` -} - -func (r *AllowedValueRange) clean() { - cleanWhitespace(&r.Minimum) - cleanWhitespace(&r.Maximum) - cleanWhitespace(&r.Step) -} - -type DataType struct { - Name string `xml:",chardata"` - Type string `xml:"type,attr"` -} - -func (dt *DataType) clean() { - cleanWhitespace(&dt.Name) - cleanWhitespace(&dt.Type) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go b/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go deleted file mode 100644 index ec6227888..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/service_client.go +++ /dev/null @@ -1,56 +0,0 @@ -package goupnp - -import ( - "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/soap" -) - -// ServiceClient is a SOAP client, root device and the service for the SOAP -// client rolled into one value. The root device and service are intended to be -// informational. -type ServiceClient struct { - SOAPClient *soap.SOAPClient - RootDevice *RootDevice - Service *Service -} - -func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []error, err error) { - var maybeRootDevices []MaybeRootDevice - if maybeRootDevices, err = DiscoverDevices(searchTarget); err != nil { - return - } - - clients = make([]ServiceClient, 0, len(maybeRootDevices)) - - for _, maybeRootDevice := range maybeRootDevices { - if maybeRootDevice.Err != nil { - errors = append(errors, maybeRootDevice.Err) - continue - } - - device := &maybeRootDevice.Root.Device - srvs := device.FindService(searchTarget) - if len(srvs) == 0 { - errors = append(errors, fmt.Errorf("goupnp: service %q not found within device %q (UDN=%q)", - searchTarget, device.FriendlyName, device.UDN)) - continue - } - - for _, srv := range srvs { - clients = append(clients, ServiceClient{ - SOAPClient: srv.NewSOAPClient(), - RootDevice: maybeRootDevice.Root, - Service: srv, - }) - } - } - - return -} - -// GetServiceClient returns the ServiceClient itself. This is provided so that the -// service client attributes can be accessed via an interface method on a -// wrapping type. -func (client *ServiceClient) GetServiceClient() *ServiceClient { - return client -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go deleted file mode 100644 index 33cbe283c..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go +++ /dev/null @@ -1,157 +0,0 @@ -// Definition for the SOAP structure required for UPnP's SOAP usage. - -package soap - -import ( - "bytes" - "encoding/xml" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "reflect" -) - -const ( - soapEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" - soapPrefix = xml.Header + `` - soapSuffix = `` -) - -type SOAPClient struct { - EndpointURL url.URL - HTTPClient http.Client -} - -func NewSOAPClient(endpointURL url.URL) *SOAPClient { - return &SOAPClient{ - EndpointURL: endpointURL, - } -} - -// PerformSOAPAction makes a SOAP request, with the given action. -// inAction and outAction must both be pointers to structs with string fields -// only. -func (client *SOAPClient) PerformAction(actionNamespace, actionName string, inAction interface{}, outAction interface{}) error { - requestBytes, err := encodeRequestAction(actionNamespace, actionName, inAction) - if err != nil { - return err - } - - response, err := client.HTTPClient.Do(&http.Request{ - Method: "POST", - URL: &client.EndpointURL, - Header: http.Header{ - "SOAPACTION": []string{actionNamespace + "#" + actionName}, - "CONTENT-TYPE": []string{"text/xml; charset=\"utf-8\""}, - }, - Body: ioutil.NopCloser(bytes.NewBuffer(requestBytes)), - // Set ContentLength to avoid chunked encoding - some servers might not support it. - ContentLength: int64(len(requestBytes)), - }) - if err != nil { - return fmt.Errorf("goupnp: error performing SOAP HTTP request: %v", err) - } - defer response.Body.Close() - if response.StatusCode != 200 { - return fmt.Errorf("goupnp: SOAP request got HTTP %s", response.Status) - } - - responseEnv := newSOAPEnvelope() - decoder := xml.NewDecoder(response.Body) - if err := decoder.Decode(responseEnv); err != nil { - return fmt.Errorf("goupnp: error decoding response body: %v", err) - } - - if responseEnv.Body.Fault != nil { - return responseEnv.Body.Fault - } - - if outAction != nil { - if err := xml.Unmarshal(responseEnv.Body.RawAction, outAction); err != nil { - return fmt.Errorf("goupnp: error unmarshalling out action: %v, %v", err, responseEnv.Body.RawAction) - } - } - - return nil -} - -// newSOAPAction creates a soapEnvelope with the given action and arguments. -func newSOAPEnvelope() *soapEnvelope { - return &soapEnvelope{ - EncodingStyle: soapEncodingStyle, - } -} - -// encodeRequestAction is a hacky way to create an encoded SOAP envelope -// containing the given action. Experiments with one router have shown that it -// 500s for requests where the outer default xmlns is set to the SOAP -// namespace, and then reassigning the default namespace within that to the -// service namespace. Hand-coding the outer XML to work-around this. -func encodeRequestAction(actionNamespace, actionName string, inAction interface{}) ([]byte, error) { - requestBuf := new(bytes.Buffer) - requestBuf.WriteString(soapPrefix) - requestBuf.WriteString(``) - if inAction != nil { - if err := encodeRequestArgs(requestBuf, inAction); err != nil { - return nil, err - } - } - requestBuf.WriteString(``) - requestBuf.WriteString(soapSuffix) - return requestBuf.Bytes(), nil -} - -func encodeRequestArgs(w *bytes.Buffer, inAction interface{}) error { - in := reflect.Indirect(reflect.ValueOf(inAction)) - if in.Kind() != reflect.Struct { - return fmt.Errorf("goupnp: SOAP inAction is not a struct but of type %v", in.Type()) - } - enc := xml.NewEncoder(w) - nFields := in.NumField() - inType := in.Type() - for i := 0; i < nFields; i++ { - field := inType.Field(i) - argName := field.Name - if nameOverride := field.Tag.Get("soap"); nameOverride != "" { - argName = nameOverride - } - value := in.Field(i) - if value.Kind() != reflect.String { - return fmt.Errorf("goupnp: SOAP arg %q is not of type string, but of type %v", argName, value.Type()) - } - if err := enc.EncodeElement(value.Interface(), xml.StartElement{xml.Name{"", argName}, nil}); err != nil { - return fmt.Errorf("goupnp: error encoding SOAP arg %q: %v", argName, err) - } - } - enc.Flush() - return nil -} - -type soapEnvelope struct { - XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"` - EncodingStyle string `xml:"http://schemas.xmlsoap.org/soap/envelope/ encodingStyle,attr"` - Body soapBody `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"` -} - -type soapBody struct { - Fault *SOAPFaultError `xml:"Fault"` - RawAction []byte `xml:",innerxml"` -} - -// SOAPFaultError implements error, and contains SOAP fault information. -type SOAPFaultError struct { - FaultCode string `xml:"faultcode"` - FaultString string `xml:"faultstring"` - Detail string `xml:"detail"` -} - -func (err *SOAPFaultError) Error() string { - return fmt.Sprintf("SOAP fault: %s", err.FaultString) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go deleted file mode 100644 index 75dbbdbf1..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package soap - -import ( - "bytes" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "testing" -) - -type capturingRoundTripper struct { - err error - resp *http.Response - capturedReq *http.Request -} - -func (rt *capturingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - rt.capturedReq = req - return rt.resp, rt.err -} - -func TestActionInputs(t *testing.T) { - url, err := url.Parse("http://example.com/soap") - if err != nil { - t.Fatal(err) - } - rt := &capturingRoundTripper{ - err: nil, - resp: &http.Response{ - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(` - - - - valueA - valueB - - - - `)), - }, - } - client := SOAPClient{ - EndpointURL: *url, - HTTPClient: http.Client{ - Transport: rt, - }, - } - - type In struct { - Foo string - Bar string `soap:"bar"` - } - type Out struct { - A string - B string - } - in := In{"foo", "bar"} - gotOut := Out{} - err = client.PerformAction("mynamespace", "myaction", &in, &gotOut) - if err != nil { - t.Fatal(err) - } - - wantBody := (soapPrefix + - `` + - `foo` + - `bar` + - `` + - soapSuffix) - body, err := ioutil.ReadAll(rt.capturedReq.Body) - if err != nil { - t.Fatal(err) - } - gotBody := string(body) - if wantBody != gotBody { - t.Errorf("Bad request body\nwant: %q\n got: %q", wantBody, gotBody) - } - - wantOut := Out{"valueA", "valueB"} - if !reflect.DeepEqual(wantOut, gotOut) { - t.Errorf("Bad output\nwant: %+v\n got: %+v", wantOut, gotOut) - } -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go deleted file mode 100644 index cd16510e3..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types.go +++ /dev/null @@ -1,508 +0,0 @@ -package soap - -import ( - "encoding/base64" - "encoding/hex" - "errors" - "fmt" - "regexp" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -var ( - // localLoc acts like time.Local for this package, but is faked out by the - // unit tests to ensure that things stay constant (especially when running - // this test in a place where local time is UTC which might mask bugs). - localLoc = time.Local -) - -func MarshalUi1(v uint8) (string, error) { - return strconv.FormatUint(uint64(v), 10), nil -} - -func UnmarshalUi1(s string) (uint8, error) { - v, err := strconv.ParseUint(s, 10, 8) - return uint8(v), err -} - -func MarshalUi2(v uint16) (string, error) { - return strconv.FormatUint(uint64(v), 10), nil -} - -func UnmarshalUi2(s string) (uint16, error) { - v, err := strconv.ParseUint(s, 10, 16) - return uint16(v), err -} - -func MarshalUi4(v uint32) (string, error) { - return strconv.FormatUint(uint64(v), 10), nil -} - -func UnmarshalUi4(s string) (uint32, error) { - v, err := strconv.ParseUint(s, 10, 32) - return uint32(v), err -} - -func MarshalI1(v int8) (string, error) { - return strconv.FormatInt(int64(v), 10), nil -} - -func UnmarshalI1(s string) (int8, error) { - v, err := strconv.ParseInt(s, 10, 8) - return int8(v), err -} - -func MarshalI2(v int16) (string, error) { - return strconv.FormatInt(int64(v), 10), nil -} - -func UnmarshalI2(s string) (int16, error) { - v, err := strconv.ParseInt(s, 10, 16) - return int16(v), err -} - -func MarshalI4(v int32) (string, error) { - return strconv.FormatInt(int64(v), 10), nil -} - -func UnmarshalI4(s string) (int32, error) { - v, err := strconv.ParseInt(s, 10, 32) - return int32(v), err -} - -func MarshalInt(v int64) (string, error) { - return strconv.FormatInt(v, 10), nil -} - -func UnmarshalInt(s string) (int64, error) { - return strconv.ParseInt(s, 10, 64) -} - -func MarshalR4(v float32) (string, error) { - return strconv.FormatFloat(float64(v), 'G', -1, 32), nil -} - -func UnmarshalR4(s string) (float32, error) { - v, err := strconv.ParseFloat(s, 32) - return float32(v), err -} - -func MarshalR8(v float64) (string, error) { - return strconv.FormatFloat(v, 'G', -1, 64), nil -} - -func UnmarshalR8(s string) (float64, error) { - v, err := strconv.ParseFloat(s, 64) - return float64(v), err -} - -// MarshalFixed14_4 marshals float64 to SOAP "fixed.14.4" type. -func MarshalFixed14_4(v float64) (string, error) { - if v >= 1e14 || v <= -1e14 { - return "", fmt.Errorf("soap fixed14.4: value %v out of bounds", v) - } - return strconv.FormatFloat(v, 'f', 4, 64), nil -} - -// UnmarshalFixed14_4 unmarshals float64 from SOAP "fixed.14.4" type. -func UnmarshalFixed14_4(s string) (float64, error) { - v, err := strconv.ParseFloat(s, 64) - if err != nil { - return 0, err - } - if v >= 1e14 || v <= -1e14 { - return 0, fmt.Errorf("soap fixed14.4: value %q out of bounds", s) - } - return v, nil -} - -// MarshalChar marshals rune to SOAP "char" type. -func MarshalChar(v rune) (string, error) { - if v == 0 { - return "", errors.New("soap char: rune 0 is not allowed") - } - return string(v), nil -} - -// UnmarshalChar unmarshals rune from SOAP "char" type. -func UnmarshalChar(s string) (rune, error) { - if len(s) == 0 { - return 0, errors.New("soap char: got empty string") - } - r, n := utf8.DecodeRune([]byte(s)) - if n != len(s) { - return 0, fmt.Errorf("soap char: value %q is not a single rune", s) - } - return r, nil -} - -func MarshalString(v string) (string, error) { - return v, nil -} - -func UnmarshalString(v string) (string, error) { - return v, nil -} - -func parseInt(s string, err *error) int { - v, parseErr := strconv.ParseInt(s, 10, 64) - if parseErr != nil { - *err = parseErr - } - return int(v) -} - -var dateRegexps = []*regexp.Regexp{ - // yyyy[-mm[-dd]] - regexp.MustCompile(`^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?$`), - // yyyy[mm[dd]] - regexp.MustCompile(`^(\d{4})(?:(\d{2})(?:(\d{2}))?)?$`), -} - -func parseDateParts(s string) (year, month, day int, err error) { - var parts []string - for _, re := range dateRegexps { - parts = re.FindStringSubmatch(s) - if parts != nil { - break - } - } - if parts == nil { - err = fmt.Errorf("soap date: value %q is not in a recognized ISO8601 date format", s) - return - } - - year = parseInt(parts[1], &err) - month = 1 - day = 1 - if len(parts[2]) != 0 { - month = parseInt(parts[2], &err) - if len(parts[3]) != 0 { - day = parseInt(parts[3], &err) - } - } - - if err != nil { - err = fmt.Errorf("soap date: %q: %v", s, err) - } - - return -} - -var timeRegexps = []*regexp.Regexp{ - // hh[:mm[:ss]] - regexp.MustCompile(`^(\d{2})(?::(\d{2})(?::(\d{2}))?)?$`), - // hh[mm[ss]] - regexp.MustCompile(`^(\d{2})(?:(\d{2})(?:(\d{2}))?)?$`), -} - -func parseTimeParts(s string) (hour, minute, second int, err error) { - var parts []string - for _, re := range timeRegexps { - parts = re.FindStringSubmatch(s) - if parts != nil { - break - } - } - if parts == nil { - err = fmt.Errorf("soap time: value %q is not in ISO8601 time format", s) - return - } - - hour = parseInt(parts[1], &err) - if len(parts[2]) != 0 { - minute = parseInt(parts[2], &err) - if len(parts[3]) != 0 { - second = parseInt(parts[3], &err) - } - } - - if err != nil { - err = fmt.Errorf("soap time: %q: %v", s, err) - } - - return -} - -// (+|-)hh[[:]mm] -var timezoneRegexp = regexp.MustCompile(`^([+-])(\d{2})(?::?(\d{2}))?$`) - -func parseTimezone(s string) (offset int, err error) { - if s == "Z" { - return 0, nil - } - parts := timezoneRegexp.FindStringSubmatch(s) - if parts == nil { - err = fmt.Errorf("soap timezone: value %q is not in ISO8601 timezone format", s) - return - } - - offset = parseInt(parts[2], &err) * 3600 - if len(parts[3]) != 0 { - offset += parseInt(parts[3], &err) * 60 - } - if parts[1] == "-" { - offset = -offset - } - - if err != nil { - err = fmt.Errorf("soap timezone: %q: %v", s, err) - } - - return -} - -var completeDateTimeZoneRegexp = regexp.MustCompile(`^([^T]+)(?:T([^-+Z]+)(.+)?)?$`) - -// splitCompleteDateTimeZone splits date, time and timezone apart from an -// ISO8601 string. It does not ensure that the contents of each part are -// correct, it merely splits on certain delimiters. -// e.g "2010-09-08T12:15:10+0700" => "2010-09-08", "12:15:10", "+0700". -// Timezone can only be present if time is also present. -func splitCompleteDateTimeZone(s string) (dateStr, timeStr, zoneStr string, err error) { - parts := completeDateTimeZoneRegexp.FindStringSubmatch(s) - if parts == nil { - err = fmt.Errorf("soap date/time/zone: value %q is not in ISO8601 datetime format", s) - return - } - dateStr = parts[1] - timeStr = parts[2] - zoneStr = parts[3] - return -} - -// MarshalDate marshals time.Time to SOAP "date" type. Note that this converts -// to local time, and discards the time-of-day components. -func MarshalDate(v time.Time) (string, error) { - return v.In(localLoc).Format("2006-01-02"), nil -} - -var dateFmts = []string{"2006-01-02", "20060102"} - -// UnmarshalDate unmarshals time.Time from SOAP "date" type. This outputs the -// date as midnight in the local time zone. -func UnmarshalDate(s string) (time.Time, error) { - year, month, day, err := parseDateParts(s) - if err != nil { - return time.Time{}, err - } - return time.Date(year, time.Month(month), day, 0, 0, 0, 0, localLoc), nil -} - -// TimeOfDay is used in cases where SOAP "time" or "time.tz" is used. -type TimeOfDay struct { - // Duration of time since midnight. - FromMidnight time.Duration - - // Set to true if Offset is specified. If false, then the timezone is - // unspecified (and by ISO8601 - implies some "local" time). - HasOffset bool - - // Offset is non-zero only if time.tz is used. It is otherwise ignored. If - // non-zero, then it is regarded as a UTC offset in seconds. Note that the - // sub-minutes is ignored by the marshal function. - Offset int -} - -// MarshalTimeOfDay marshals TimeOfDay to the "time" type. -func MarshalTimeOfDay(v TimeOfDay) (string, error) { - d := int64(v.FromMidnight / time.Second) - hour := d / 3600 - d = d % 3600 - minute := d / 60 - second := d % 60 - - return fmt.Sprintf("%02d:%02d:%02d", hour, minute, second), nil -} - -// UnmarshalTimeOfDay unmarshals TimeOfDay from the "time" type. -func UnmarshalTimeOfDay(s string) (TimeOfDay, error) { - t, err := UnmarshalTimeOfDayTz(s) - if err != nil { - return TimeOfDay{}, err - } else if t.HasOffset { - return TimeOfDay{}, fmt.Errorf("soap time: value %q contains unexpected timezone") - } - return t, nil -} - -// MarshalTimeOfDayTz marshals TimeOfDay to the "time.tz" type. -func MarshalTimeOfDayTz(v TimeOfDay) (string, error) { - d := int64(v.FromMidnight / time.Second) - hour := d / 3600 - d = d % 3600 - minute := d / 60 - second := d % 60 - - tz := "" - if v.HasOffset { - if v.Offset == 0 { - tz = "Z" - } else { - offsetMins := v.Offset / 60 - sign := '+' - if offsetMins < 1 { - offsetMins = -offsetMins - sign = '-' - } - tz = fmt.Sprintf("%c%02d:%02d", sign, offsetMins/60, offsetMins%60) - } - } - - return fmt.Sprintf("%02d:%02d:%02d%s", hour, minute, second, tz), nil -} - -// UnmarshalTimeOfDayTz unmarshals TimeOfDay from the "time.tz" type. -func UnmarshalTimeOfDayTz(s string) (tod TimeOfDay, err error) { - zoneIndex := strings.IndexAny(s, "Z+-") - var timePart string - var hasOffset bool - var offset int - if zoneIndex == -1 { - hasOffset = false - timePart = s - } else { - hasOffset = true - timePart = s[:zoneIndex] - if offset, err = parseTimezone(s[zoneIndex:]); err != nil { - return - } - } - - hour, minute, second, err := parseTimeParts(timePart) - if err != nil { - return - } - - fromMidnight := time.Duration(hour*3600+minute*60+second) * time.Second - - // ISO8601 special case - values up to 24:00:00 are allowed, so using - // strictly greater-than for the maximum value. - if fromMidnight > 24*time.Hour || minute >= 60 || second >= 60 { - return TimeOfDay{}, fmt.Errorf("soap time.tz: value %q has value(s) out of range", s) - } - - return TimeOfDay{ - FromMidnight: time.Duration(hour*3600+minute*60+second) * time.Second, - HasOffset: hasOffset, - Offset: offset, - }, nil -} - -// MarshalDateTime marshals time.Time to SOAP "dateTime" type. Note that this -// converts to local time. -func MarshalDateTime(v time.Time) (string, error) { - return v.In(localLoc).Format("2006-01-02T15:04:05"), nil -} - -// UnmarshalDateTime unmarshals time.Time from the SOAP "dateTime" type. This -// returns a value in the local timezone. -func UnmarshalDateTime(s string) (result time.Time, err error) { - dateStr, timeStr, zoneStr, err := splitCompleteDateTimeZone(s) - if err != nil { - return - } - - if len(zoneStr) != 0 { - err = fmt.Errorf("soap datetime: unexpected timezone in %q", s) - return - } - - year, month, day, err := parseDateParts(dateStr) - if err != nil { - return - } - - var hour, minute, second int - if len(timeStr) != 0 { - hour, minute, second, err = parseTimeParts(timeStr) - if err != nil { - return - } - } - - result = time.Date(year, time.Month(month), day, hour, minute, second, 0, localLoc) - return -} - -// MarshalDateTimeTz marshals time.Time to SOAP "dateTime.tz" type. -func MarshalDateTimeTz(v time.Time) (string, error) { - return v.Format("2006-01-02T15:04:05-07:00"), nil -} - -// UnmarshalDateTimeTz unmarshals time.Time from the SOAP "dateTime.tz" type. -// This returns a value in the local timezone when the timezone is unspecified. -func UnmarshalDateTimeTz(s string) (result time.Time, err error) { - dateStr, timeStr, zoneStr, err := splitCompleteDateTimeZone(s) - if err != nil { - return - } - - year, month, day, err := parseDateParts(dateStr) - if err != nil { - return - } - - var hour, minute, second int - var location *time.Location = localLoc - if len(timeStr) != 0 { - hour, minute, second, err = parseTimeParts(timeStr) - if err != nil { - return - } - if len(zoneStr) != 0 { - var offset int - offset, err = parseTimezone(zoneStr) - if offset == 0 { - location = time.UTC - } else { - location = time.FixedZone("", offset) - } - } - } - - result = time.Date(year, time.Month(month), day, hour, minute, second, 0, location) - return -} - -// MarshalBoolean marshals bool to SOAP "boolean" type. -func MarshalBoolean(v bool) (string, error) { - if v { - return "1", nil - } - return "0", nil -} - -// UnmarshalBoolean unmarshals bool from the SOAP "boolean" type. -func UnmarshalBoolean(s string) (bool, error) { - switch s { - case "0", "false", "no": - return false, nil - case "1", "true", "yes": - return true, nil - } - return false, fmt.Errorf("soap boolean: %q is not a valid boolean value", s) -} - -// MarshalBinBase64 marshals []byte to SOAP "bin.base64" type. -func MarshalBinBase64(v []byte) (string, error) { - return base64.StdEncoding.EncodeToString(v), nil -} - -// UnmarshalBinBase64 unmarshals []byte from the SOAP "bin.base64" type. -func UnmarshalBinBase64(s string) ([]byte, error) { - return base64.StdEncoding.DecodeString(s) -} - -// MarshalBinHex marshals []byte to SOAP "bin.hex" type. -func MarshalBinHex(v []byte) (string, error) { - return hex.EncodeToString(v), nil -} - -// UnmarshalBinHex unmarshals []byte from the SOAP "bin.hex" type. -func UnmarshalBinHex(s string) ([]byte, error) { - return hex.DecodeString(s) -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go deleted file mode 100644 index da6816190..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/soap/types_test.go +++ /dev/null @@ -1,481 +0,0 @@ -package soap - -import ( - "bytes" - "math" - "testing" - "time" -) - -type convTest interface { - Marshal() (string, error) - Unmarshal(string) (interface{}, error) - Equal(result interface{}) bool -} - -// duper is an interface that convTest values may optionally also implement to -// generate another convTest for a value in an otherwise identical testCase. -type duper interface { - Dupe(tag string) []convTest -} - -type testCase struct { - value convTest - str string - wantMarshalErr bool - wantUnmarshalErr bool - noMarshal bool - noUnMarshal bool - tag string -} - -type Ui1Test uint8 - -func (v Ui1Test) Marshal() (string, error) { - return MarshalUi1(uint8(v)) -} -func (v Ui1Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalUi1(s) -} -func (v Ui1Test) Equal(result interface{}) bool { - return uint8(v) == result.(uint8) -} -func (v Ui1Test) Dupe(tag string) []convTest { - if tag == "dupe" { - return []convTest{ - Ui2Test(v), - Ui4Test(v), - } - } - return nil -} - -type Ui2Test uint16 - -func (v Ui2Test) Marshal() (string, error) { - return MarshalUi2(uint16(v)) -} -func (v Ui2Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalUi2(s) -} -func (v Ui2Test) Equal(result interface{}) bool { - return uint16(v) == result.(uint16) -} - -type Ui4Test uint32 - -func (v Ui4Test) Marshal() (string, error) { - return MarshalUi4(uint32(v)) -} -func (v Ui4Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalUi4(s) -} -func (v Ui4Test) Equal(result interface{}) bool { - return uint32(v) == result.(uint32) -} - -type I1Test int8 - -func (v I1Test) Marshal() (string, error) { - return MarshalI1(int8(v)) -} -func (v I1Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalI1(s) -} -func (v I1Test) Equal(result interface{}) bool { - return int8(v) == result.(int8) -} -func (v I1Test) Dupe(tag string) []convTest { - if tag == "dupe" { - return []convTest{ - I2Test(v), - I4Test(v), - } - } - return nil -} - -type I2Test int16 - -func (v I2Test) Marshal() (string, error) { - return MarshalI2(int16(v)) -} -func (v I2Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalI2(s) -} -func (v I2Test) Equal(result interface{}) bool { - return int16(v) == result.(int16) -} - -type I4Test int32 - -func (v I4Test) Marshal() (string, error) { - return MarshalI4(int32(v)) -} -func (v I4Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalI4(s) -} -func (v I4Test) Equal(result interface{}) bool { - return int32(v) == result.(int32) -} - -type IntTest int64 - -func (v IntTest) Marshal() (string, error) { - return MarshalInt(int64(v)) -} -func (v IntTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalInt(s) -} -func (v IntTest) Equal(result interface{}) bool { - return int64(v) == result.(int64) -} - -type Fixed14_4Test float64 - -func (v Fixed14_4Test) Marshal() (string, error) { - return MarshalFixed14_4(float64(v)) -} -func (v Fixed14_4Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalFixed14_4(s) -} -func (v Fixed14_4Test) Equal(result interface{}) bool { - return math.Abs(float64(v)-result.(float64)) < 0.001 -} - -type CharTest rune - -func (v CharTest) Marshal() (string, error) { - return MarshalChar(rune(v)) -} -func (v CharTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalChar(s) -} -func (v CharTest) Equal(result interface{}) bool { - return rune(v) == result.(rune) -} - -type DateTest struct{ time.Time } - -func (v DateTest) Marshal() (string, error) { - return MarshalDate(time.Time(v.Time)) -} -func (v DateTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalDate(s) -} -func (v DateTest) Equal(result interface{}) bool { - return v.Time.Equal(result.(time.Time)) -} -func (v DateTest) Dupe(tag string) []convTest { - if tag != "no:dateTime" { - return []convTest{DateTimeTest{v.Time}} - } - return nil -} - -type TimeOfDayTest struct { - TimeOfDay -} - -func (v TimeOfDayTest) Marshal() (string, error) { - return MarshalTimeOfDay(v.TimeOfDay) -} -func (v TimeOfDayTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalTimeOfDay(s) -} -func (v TimeOfDayTest) Equal(result interface{}) bool { - return v.TimeOfDay == result.(TimeOfDay) -} -func (v TimeOfDayTest) Dupe(tag string) []convTest { - if tag != "no:time.tz" { - return []convTest{TimeOfDayTzTest{v.TimeOfDay}} - } - return nil -} - -type TimeOfDayTzTest struct { - TimeOfDay -} - -func (v TimeOfDayTzTest) Marshal() (string, error) { - return MarshalTimeOfDayTz(v.TimeOfDay) -} -func (v TimeOfDayTzTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalTimeOfDayTz(s) -} -func (v TimeOfDayTzTest) Equal(result interface{}) bool { - return v.TimeOfDay == result.(TimeOfDay) -} - -type DateTimeTest struct{ time.Time } - -func (v DateTimeTest) Marshal() (string, error) { - return MarshalDateTime(time.Time(v.Time)) -} -func (v DateTimeTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalDateTime(s) -} -func (v DateTimeTest) Equal(result interface{}) bool { - return v.Time.Equal(result.(time.Time)) -} -func (v DateTimeTest) Dupe(tag string) []convTest { - if tag != "no:dateTime.tz" { - return []convTest{DateTimeTzTest{v.Time}} - } - return nil -} - -type DateTimeTzTest struct{ time.Time } - -func (v DateTimeTzTest) Marshal() (string, error) { - return MarshalDateTimeTz(time.Time(v.Time)) -} -func (v DateTimeTzTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalDateTimeTz(s) -} -func (v DateTimeTzTest) Equal(result interface{}) bool { - return v.Time.Equal(result.(time.Time)) -} - -type BooleanTest bool - -func (v BooleanTest) Marshal() (string, error) { - return MarshalBoolean(bool(v)) -} -func (v BooleanTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalBoolean(s) -} -func (v BooleanTest) Equal(result interface{}) bool { - return bool(v) == result.(bool) -} - -type BinBase64Test []byte - -func (v BinBase64Test) Marshal() (string, error) { - return MarshalBinBase64([]byte(v)) -} -func (v BinBase64Test) Unmarshal(s string) (interface{}, error) { - return UnmarshalBinBase64(s) -} -func (v BinBase64Test) Equal(result interface{}) bool { - return bytes.Equal([]byte(v), result.([]byte)) -} - -type BinHexTest []byte - -func (v BinHexTest) Marshal() (string, error) { - return MarshalBinHex([]byte(v)) -} -func (v BinHexTest) Unmarshal(s string) (interface{}, error) { - return UnmarshalBinHex(s) -} -func (v BinHexTest) Equal(result interface{}) bool { - return bytes.Equal([]byte(v), result.([]byte)) -} - -func Test(t *testing.T) { - const time010203 time.Duration = (1*3600 + 2*60 + 3) * time.Second - const time0102 time.Duration = (1*3600 + 2*60) * time.Second - const time01 time.Duration = (1 * 3600) * time.Second - const time235959 time.Duration = (23*3600 + 59*60 + 59) * time.Second - - // Fake out the local time for the implementation. - localLoc = time.FixedZone("Fake/Local", 6*3600) - defer func() { - localLoc = time.Local - }() - - tests := []testCase{ - // ui1 - {str: "", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: " ", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: "abc", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: "-1", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: "0", value: Ui1Test(0), tag: "dupe"}, - {str: "1", value: Ui1Test(1), tag: "dupe"}, - {str: "255", value: Ui1Test(255), tag: "dupe"}, - {str: "256", value: Ui1Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // ui2 - {str: "65535", value: Ui2Test(65535)}, - {str: "65536", value: Ui2Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // ui4 - {str: "4294967295", value: Ui4Test(4294967295)}, - {str: "4294967296", value: Ui4Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // i1 - {str: "", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: " ", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: "abc", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true, tag: "dupe"}, - {str: "0", value: I1Test(0), tag: "dupe"}, - {str: "-1", value: I1Test(-1), tag: "dupe"}, - {str: "127", value: I1Test(127), tag: "dupe"}, - {str: "-128", value: I1Test(-128), tag: "dupe"}, - {str: "128", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true}, - {str: "-129", value: I1Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // i2 - {str: "32767", value: I2Test(32767)}, - {str: "-32768", value: I2Test(-32768)}, - {str: "32768", value: I2Test(0), wantUnmarshalErr: true, noMarshal: true}, - {str: "-32769", value: I2Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // i4 - {str: "2147483647", value: I4Test(2147483647)}, - {str: "-2147483648", value: I4Test(-2147483648)}, - {str: "2147483648", value: I4Test(0), wantUnmarshalErr: true, noMarshal: true}, - {str: "-2147483649", value: I4Test(0), wantUnmarshalErr: true, noMarshal: true}, - - // int - {str: "9223372036854775807", value: IntTest(9223372036854775807)}, - {str: "-9223372036854775808", value: IntTest(-9223372036854775808)}, - {str: "9223372036854775808", value: IntTest(0), wantUnmarshalErr: true, noMarshal: true}, - {str: "-9223372036854775809", value: IntTest(0), wantUnmarshalErr: true, noMarshal: true}, - - // fixed.14.4 - {str: "0.0000", value: Fixed14_4Test(0)}, - {str: "1.0000", value: Fixed14_4Test(1)}, - {str: "1.2346", value: Fixed14_4Test(1.23456)}, - {str: "-1.0000", value: Fixed14_4Test(-1)}, - {str: "-1.2346", value: Fixed14_4Test(-1.23456)}, - {str: "10000000000000.0000", value: Fixed14_4Test(1e13)}, - {str: "100000000000000.0000", value: Fixed14_4Test(1e14), wantMarshalErr: true, wantUnmarshalErr: true}, - {str: "-10000000000000.0000", value: Fixed14_4Test(-1e13)}, - {str: "-100000000000000.0000", value: Fixed14_4Test(-1e14), wantMarshalErr: true, wantUnmarshalErr: true}, - - // char - {str: "a", value: CharTest('a')}, - {str: "z", value: CharTest('z')}, - {str: "\u1234", value: CharTest(0x1234)}, - {str: "aa", value: CharTest(0), wantMarshalErr: true, wantUnmarshalErr: true}, - {str: "", value: CharTest(0), wantMarshalErr: true, wantUnmarshalErr: true}, - - // date - {str: "2013-10-08", value: DateTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, tag: "no:dateTime"}, - {str: "20131008", value: DateTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, noMarshal: true, tag: "no:dateTime"}, - {str: "2013-10-08T10:30:50", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime"}, - {str: "2013-10-08T10:30:50Z", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime"}, - {str: "", value: DateTest{}, wantMarshalErr: true, wantUnmarshalErr: true, noMarshal: true}, - {str: "-1", value: DateTest{}, wantUnmarshalErr: true, noMarshal: true}, - - // time - {str: "00:00:00", value: TimeOfDayTest{TimeOfDay{FromMidnight: 0}}}, - {str: "000000", value: TimeOfDayTest{TimeOfDay{FromMidnight: 0}}, noMarshal: true}, - {str: "24:00:00", value: TimeOfDayTest{TimeOfDay{FromMidnight: 24 * time.Hour}}, noMarshal: true}, // ISO8601 special case - {str: "24:01:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "24:00:01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "25:00:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "00:60:00", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "00:00:60", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "01:02:03", value: TimeOfDayTest{TimeOfDay{FromMidnight: time010203}}}, - {str: "010203", value: TimeOfDayTest{TimeOfDay{FromMidnight: time010203}}, noMarshal: true}, - {str: "23:59:59", value: TimeOfDayTest{TimeOfDay{FromMidnight: time235959}}}, - {str: "235959", value: TimeOfDayTest{TimeOfDay{FromMidnight: time235959}}, noMarshal: true}, - {str: "01:02", value: TimeOfDayTest{TimeOfDay{FromMidnight: time0102}}, noMarshal: true}, - {str: "0102", value: TimeOfDayTest{TimeOfDay{FromMidnight: time0102}}, noMarshal: true}, - {str: "01", value: TimeOfDayTest{TimeOfDay{FromMidnight: time01}}, noMarshal: true}, - {str: "foo 01:02:03", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "foo\n01:02:03", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03 foo", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03\nfoo", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03Z", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03+01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03+01:23", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03+0123", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03-01", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03-01:23", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - {str: "01:02:03-0123", value: TimeOfDayTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:time.tz"}, - - // time.tz - {str: "24:00:01", value: TimeOfDayTzTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "01Z", value: TimeOfDayTzTest{TimeOfDay{time01, true, 0}}, noMarshal: true}, - {str: "01:02:03Z", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 0}}}, - {str: "01+01", value: TimeOfDayTzTest{TimeOfDay{time01, true, 3600}}, noMarshal: true}, - {str: "01:02:03+01", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600}}, noMarshal: true}, - {str: "01:02:03+01:23", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600 + 23*60}}}, - {str: "01:02:03+0123", value: TimeOfDayTzTest{TimeOfDay{time010203, true, 3600 + 23*60}}, noMarshal: true}, - {str: "01:02:03-01", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -3600}}, noMarshal: true}, - {str: "01:02:03-01:23", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -(3600 + 23*60)}}}, - {str: "01:02:03-0123", value: TimeOfDayTzTest{TimeOfDay{time010203, true, -(3600 + 23*60)}}, noMarshal: true}, - - // dateTime - {str: "2013-10-08T00:00:00", value: DateTimeTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, tag: "no:dateTime.tz"}, - {str: "20131008", value: DateTimeTest{time.Date(2013, 10, 8, 0, 0, 0, 0, localLoc)}, noMarshal: true}, - {str: "2013-10-08T10:30:50", value: DateTimeTest{time.Date(2013, 10, 8, 10, 30, 50, 0, localLoc)}, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50T", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true}, - {str: "2013-10-08T10:30:50+01", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50+01:23", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50+0123", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50-01", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50-01:23", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - {str: "2013-10-08T10:30:50-0123", value: DateTimeTest{}, wantUnmarshalErr: true, noMarshal: true, tag: "no:dateTime.tz"}, - - // dateTime.tz - {str: "2013-10-08T10:30:50", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, localLoc)}, noMarshal: true}, - {str: "2013-10-08T10:30:50+01", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:00", 3600))}, noMarshal: true}, - {str: "2013-10-08T10:30:50+01:23", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:23", 3600+23*60))}}, - {str: "2013-10-08T10:30:50+0123", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("+01:23", 3600+23*60))}, noMarshal: true}, - {str: "2013-10-08T10:30:50-01", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:00", -3600))}, noMarshal: true}, - {str: "2013-10-08T10:30:50-01:23", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:23", -(3600+23*60)))}}, - {str: "2013-10-08T10:30:50-0123", value: DateTimeTzTest{time.Date(2013, 10, 8, 10, 30, 50, 0, time.FixedZone("-01:23", -(3600+23*60)))}, noMarshal: true}, - - // boolean - {str: "0", value: BooleanTest(false)}, - {str: "1", value: BooleanTest(true)}, - {str: "false", value: BooleanTest(false), noMarshal: true}, - {str: "true", value: BooleanTest(true), noMarshal: true}, - {str: "no", value: BooleanTest(false), noMarshal: true}, - {str: "yes", value: BooleanTest(true), noMarshal: true}, - {str: "", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, - {str: "other", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, - {str: "2", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, - {str: "-1", value: BooleanTest(false), noMarshal: true, wantUnmarshalErr: true}, - - // bin.base64 - {str: "", value: BinBase64Test{}}, - {str: "YQ==", value: BinBase64Test("a")}, - {str: "TG9uZ2VyIFN0cmluZy4=", value: BinBase64Test("Longer String.")}, - {str: "TG9uZ2VyIEFsaWduZWQu", value: BinBase64Test("Longer Aligned.")}, - - // bin.hex - {str: "", value: BinHexTest{}}, - {str: "61", value: BinHexTest("a")}, - {str: "4c6f6e67657220537472696e672e", value: BinHexTest("Longer String.")}, - {str: "4C6F6E67657220537472696E672E", value: BinHexTest("Longer String."), noMarshal: true}, - } - - // Generate extra test cases from convTests that implement duper. - var extras []testCase - for i := range tests { - if duper, ok := tests[i].value.(duper); ok { - dupes := duper.Dupe(tests[i].tag) - for _, duped := range dupes { - dupedCase := testCase(tests[i]) - dupedCase.value = duped - extras = append(extras, dupedCase) - } - } - } - tests = append(tests, extras...) - - for _, test := range tests { - if test.noMarshal { - } else if resultStr, err := test.value.Marshal(); err != nil && !test.wantMarshalErr { - t.Errorf("For %T marshal %v, want %q, got error: %v", test.value, test.value, test.str, err) - } else if err == nil && test.wantMarshalErr { - t.Errorf("For %T marshal %v, want error, got %q", test.value, test.value, resultStr) - } else if err == nil && resultStr != test.str { - t.Errorf("For %T marshal %v, want %q, got %q", test.value, test.value, test.str, resultStr) - } - - if test.noUnMarshal { - } else if resultValue, err := test.value.Unmarshal(test.str); err != nil && !test.wantUnmarshalErr { - t.Errorf("For %T unmarshal %q, want %v, got error: %v", test.value, test.str, test.value, err) - } else if err == nil && test.wantUnmarshalErr { - t.Errorf("For %T unmarshal %q, want error, got %v", test.value, test.str, resultValue) - } else if err == nil && !test.value.Equal(resultValue) { - t.Errorf("For %T unmarshal %q, want %v, got %v", test.value, test.str, test.value, resultValue) - } - } -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go deleted file mode 100644 index c1fdac706..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/registry.go +++ /dev/null @@ -1,202 +0,0 @@ -package ssdp - -import ( - "fmt" - "log" - "net/http" - "net/url" - "regexp" - "strconv" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/httpu" -) - -const ( - maxExpiryTimeSeconds = 24 * 60 * 60 -) - -var ( - maxAgeRx = regexp.MustCompile("max-age=([0-9]+)") -) - -type Entry struct { - // The address that the entry data was actually received from. - RemoteAddr string - // Unique Service Name. Identifies a unique instance of a device or service. - USN string - // Notfication Type. The type of device or service being announced. - NT string - // Server's self-identifying string. - Server string - Host string - // Location of the UPnP root device description. - Location *url.URL - - // Despite BOOTID,CONFIGID being required fields, apparently they are not - // always set by devices. Set to -1 if not present. - - BootID int32 - ConfigID int32 - - SearchPort uint16 - - // When the last update was received for this entry identified by this USN. - LastUpdate time.Time - // When the last update's cached values are advised to expire. - CacheExpiry time.Time -} - -func newEntryFromRequest(r *http.Request) (*Entry, error) { - now := time.Now() - expiryDuration, err := parseCacheControlMaxAge(r.Header.Get("CACHE-CONTROL")) - if err != nil { - return nil, fmt.Errorf("ssdp: error parsing CACHE-CONTROL max age: %v", err) - } - - loc, err := url.Parse(r.Header.Get("LOCATION")) - if err != nil { - return nil, fmt.Errorf("ssdp: error parsing entry Location URL: %v", err) - } - - bootID, err := parseUpnpIntHeader(r.Header, "BOOTID.UPNP.ORG", -1) - if err != nil { - return nil, err - } - configID, err := parseUpnpIntHeader(r.Header, "CONFIGID.UPNP.ORG", -1) - if err != nil { - return nil, err - } - searchPort, err := parseUpnpIntHeader(r.Header, "SEARCHPORT.UPNP.ORG", ssdpSearchPort) - if err != nil { - return nil, err - } - - if searchPort < 1 || searchPort > 65535 { - return nil, fmt.Errorf("ssdp: search port %d is out of range", searchPort) - } - - return &Entry{ - RemoteAddr: r.RemoteAddr, - USN: r.Header.Get("USN"), - NT: r.Header.Get("NT"), - Server: r.Header.Get("SERVER"), - Host: r.Header.Get("HOST"), - Location: loc, - BootID: bootID, - ConfigID: configID, - SearchPort: uint16(searchPort), - LastUpdate: now, - CacheExpiry: now.Add(expiryDuration), - }, nil -} - -func parseCacheControlMaxAge(cc string) (time.Duration, error) { - matches := maxAgeRx.FindStringSubmatch(cc) - if len(matches) != 2 { - return 0, fmt.Errorf("did not find exactly one max-age in cache control header: %q", cc) - } - expirySeconds, err := strconv.ParseInt(matches[1], 10, 16) - if err != nil { - return 0, err - } - if expirySeconds < 1 || expirySeconds > maxExpiryTimeSeconds { - return 0, fmt.Errorf("rejecting bad expiry time of %d seconds", expirySeconds) - } - return time.Duration(expirySeconds) * time.Second, nil -} - -// parseUpnpIntHeader is intended to parse the -// {BOOT,CONFIGID,SEARCHPORT}.UPNP.ORG header fields. It returns the def if -// the head is empty or missing. -func parseUpnpIntHeader(headers http.Header, headerName string, def int32) (int32, error) { - s := headers.Get(headerName) - if s == "" { - return def, nil - } - v, err := strconv.ParseInt(s, 10, 32) - if err != nil { - return 0, fmt.Errorf("ssdp: could not parse header %s: %v", headerName, err) - } - return int32(v), nil -} - -var _ httpu.Handler = new(Registry) - -// Registry maintains knowledge of discovered devices and services. -type Registry struct { - lock sync.Mutex - byUSN map[string]*Entry -} - -func NewRegistry() *Registry { - return &Registry{ - byUSN: make(map[string]*Entry), - } -} - -// ServeMessage implements httpu.Handler, and uses SSDP NOTIFY requests to -// maintain the registry of devices and services. -func (reg *Registry) ServeMessage(r *http.Request) { - if r.Method != methodNotify { - return - } - - nts := r.Header.Get("nts") - - var err error - switch nts { - case ntsAlive: - err = reg.handleNTSAlive(r) - case ntsUpdate: - err = reg.handleNTSUpdate(r) - case ntsByebye: - err = reg.handleNTSByebye(r) - default: - err = fmt.Errorf("unknown NTS value: %q", nts) - } - log.Printf("In %s request from %s: %v", nts, r.RemoteAddr, err) -} - -func (reg *Registry) handleNTSAlive(r *http.Request) error { - entry, err := newEntryFromRequest(r) - if err != nil { - return err - } - - reg.lock.Lock() - defer reg.lock.Unlock() - - reg.byUSN[entry.USN] = entry - - return nil -} - -func (reg *Registry) handleNTSUpdate(r *http.Request) error { - entry, err := newEntryFromRequest(r) - if err != nil { - return err - } - nextBootID, err := parseUpnpIntHeader(r.Header, "NEXTBOOTID.UPNP.ORG", -1) - if err != nil { - return err - } - entry.BootID = nextBootID - - reg.lock.Lock() - defer reg.lock.Unlock() - - reg.byUSN[entry.USN] = entry - - return nil -} - -func (reg *Registry) handleNTSByebye(r *http.Request) error { - reg.lock.Lock() - defer reg.lock.Unlock() - - delete(reg.byUSN, r.Header.Get("USN")) - - return nil -} diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go b/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go deleted file mode 100644 index 641634462..000000000 --- a/Godeps/_workspace/src/github.com/huin/goupnp/ssdp/ssdp.go +++ /dev/null @@ -1,83 +0,0 @@ -package ssdp - -import ( - "errors" - "log" - "net/http" - "net/url" - "strconv" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/huin/goupnp/httpu" -) - -const ( - ssdpDiscover = `"ssdp:discover"` - ntsAlive = `ssdp:alive` - ntsByebye = `ssdp:byebye` - ntsUpdate = `ssdp:update` - ssdpUDP4Addr = "239.255.255.250:1900" - ssdpSearchPort = 1900 - methodSearch = "M-SEARCH" - methodNotify = "NOTIFY" -) - -// SSDPRawSearch performs a fairly raw SSDP search request, and returns the -// unique response(s) that it receives. Each response has the requested -// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to -// wait for responses in seconds, and must be a minimum of 1 (the -// implementation waits an additional 100ms for responses to arrive), 2 is a -// reasonable value for this. numSends is the number of requests to send - 3 is -// a reasonable value for this. -func SSDPRawSearch(httpu *httpu.HTTPUClient, searchTarget string, maxWaitSeconds int, numSends int) ([]*http.Response, error) { - if maxWaitSeconds < 1 { - return nil, errors.New("ssdp: maxWaitSeconds must be >= 1") - } - - seenUsns := make(map[string]bool) - var responses []*http.Response - req := http.Request{ - Method: methodSearch, - // TODO: Support both IPv4 and IPv6. - Host: ssdpUDP4Addr, - URL: &url.URL{Opaque: "*"}, - Header: http.Header{ - // Putting headers in here avoids them being title-cased. - // (The UPnP discovery protocol uses case-sensitive headers) - "HOST": []string{ssdpUDP4Addr}, - "MX": []string{strconv.FormatInt(int64(maxWaitSeconds), 10)}, - "MAN": []string{ssdpDiscover}, - "ST": []string{searchTarget}, - }, - } - allResponses, err := httpu.Do(&req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends) - if err != nil { - return nil, err - } - for _, response := range allResponses { - if response.StatusCode != 200 { - log.Printf("ssdp: got response status code %q in search response", response.Status) - continue - } - if st := response.Header.Get("ST"); st != searchTarget { - log.Printf("ssdp: got unexpected search target result %q", st) - continue - } - location, err := response.Location() - if err != nil { - log.Printf("ssdp: no usable location in search response (discarding): %v", err) - continue - } - usn := response.Header.Get("USN") - if usn == "" { - log.Printf("ssdp: empty/missing USN in search response (using location instead): %v", err) - usn = location.String() - } - if _, alreadySeen := seenUsns[usn]; !alreadySeen { - seenUsns[usn] = true - responses = append(responses, response) - } - } - - return responses, nil -} diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE deleted file mode 100644 index 249514b0f..000000000 --- a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - Copyright 2013 John Howard Palevich - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md deleted file mode 100644 index 15f72fd81..000000000 --- a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/README.md +++ /dev/null @@ -1,48 +0,0 @@ -go-nat-pmp -========== - -A Go language client for the NAT-PMP internet protocol for port mapping and discovering the external -IP address of a firewall. - -NAT-PMP is supported by Apple brand routers and open source routers like Tomato and DD-WRT. - -See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 - -Get the package ---------------- - - go get -u github.com/jackpal/go-nat-pmp - -Usage ------ - - import natpmp "github.com/jackpal/go-nat-pmp" - - client := natpmp.NewClient(gatewayIP) - response, err := client.GetExternalAddress() - if err != nil { - return - } - print("External IP address:", response.ExternalIPAddress) - -Notes ------ - -There doesn't seem to be an easy way to programmatically determine the address of the default gateway. -(Linux and OSX have a "routes" kernel API that can be examined to get this information, but there is -no Go package for getting this information.) - -Clients -------- - -This library is used in the Taipei Torrent BitTorrent client http://github.com/jackpal/Taipei-Torrent - -Complete documentation ----------------------- - - http://godoc.org/github.com/jackpal/go-nat-pmp - -License -------- - -This project is licensed under the Apache License 2.0. diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go deleted file mode 100644 index 8ce4e8342..000000000 --- a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go +++ /dev/null @@ -1,184 +0,0 @@ -package natpmp - -import ( - "fmt" - "log" - "net" - "time" -) - -// Implement the NAT-PMP protocol, typically supported by Apple routers and open source -// routers such as DD-WRT and Tomato. -// -// See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 -// -// Usage: -// -// client := natpmp.NewClient(gatewayIP) -// response, err := client.GetExternalAddress() - -const nAT_PMP_PORT = 5351 - -const nAT_TRIES = 9 - -const nAT_INITIAL_MS = 250 - -// The recommended mapping lifetime for AddPortMapping -const RECOMMENDED_MAPPING_LIFETIME_SECONDS = 3600 - -// Client is a NAT-PMP protocol client. -type Client struct { - gateway net.IP -} - -// Create a NAT-PMP client for the NAT-PMP server at the gateway. -func NewClient(gateway net.IP) (nat *Client) { - return &Client{gateway} -} - -// Results of the NAT-PMP GetExternalAddress operation -type GetExternalAddressResult struct { - SecondsSinceStartOfEpoc uint32 - ExternalIPAddress [4]byte -} - -// Get the external address of the router. -func (n *Client) GetExternalAddress() (result *GetExternalAddressResult, err error) { - msg := make([]byte, 2) - msg[0] = 0 // Version 0 - msg[1] = 0 // OP Code 0 - response, err := n.rpc(msg, 12) - if err != nil { - return - } - result = &GetExternalAddressResult{} - result.SecondsSinceStartOfEpoc = readNetworkOrderUint32(response[4:8]) - copy(result.ExternalIPAddress[:], response[8:12]) - return -} - -// Results of the NAT-PMP AddPortMapping operation -type AddPortMappingResult struct { - SecondsSinceStartOfEpoc uint32 - InternalPort uint16 - MappedExternalPort uint16 - PortMappingLifetimeInSeconds uint32 -} - -// Add (or delete) a port mapping. To delete a mapping, set the requestedExternalPort and lifetime to 0 -func (n *Client) AddPortMapping(protocol string, internalPort, requestedExternalPort int, lifetime int) (result *AddPortMappingResult, err error) { - var opcode byte - if protocol == "udp" { - opcode = 1 - } else if protocol == "tcp" { - opcode = 2 - } else { - err = fmt.Errorf("unknown protocol %v", protocol) - return - } - msg := make([]byte, 12) - msg[0] = 0 // Version 0 - msg[1] = opcode - writeNetworkOrderUint16(msg[4:6], uint16(internalPort)) - writeNetworkOrderUint16(msg[6:8], uint16(requestedExternalPort)) - writeNetworkOrderUint32(msg[8:12], uint32(lifetime)) - response, err := n.rpc(msg, 16) - if err != nil { - return - } - result = &AddPortMappingResult{} - result.SecondsSinceStartOfEpoc = readNetworkOrderUint32(response[4:8]) - result.InternalPort = readNetworkOrderUint16(response[8:10]) - result.MappedExternalPort = readNetworkOrderUint16(response[10:12]) - result.PortMappingLifetimeInSeconds = readNetworkOrderUint32(response[12:16]) - return -} - -func (n *Client) rpc(msg []byte, resultSize int) (result []byte, err error) { - var server net.UDPAddr - server.IP = n.gateway - server.Port = nAT_PMP_PORT - conn, err := net.DialUDP("udp", nil, &server) - if err != nil { - return - } - defer conn.Close() - - result = make([]byte, resultSize) - - needNewDeadline := true - - var tries uint - for tries = 0; tries < nAT_TRIES; { - if needNewDeadline { - err = conn.SetDeadline(time.Now().Add((nAT_INITIAL_MS << tries) * time.Millisecond)) - if err != nil { - return - } - needNewDeadline = false - } - _, err = conn.Write(msg) - if err != nil { - return - } - var bytesRead int - var remoteAddr *net.UDPAddr - bytesRead, remoteAddr, err = conn.ReadFromUDP(result) - if err != nil { - if err.(net.Error).Timeout() { - tries++ - needNewDeadline = true - continue - } - return - } - if !remoteAddr.IP.Equal(n.gateway) { - log.Printf("Ignoring packet because IPs differ:", remoteAddr, n.gateway) - // Ignore this packet. - // Continue without increasing retransmission timeout or deadline. - continue - } - if bytesRead != resultSize { - err = fmt.Errorf("unexpected result size %d, expected %d", bytesRead, resultSize) - return - } - if result[0] != 0 { - err = fmt.Errorf("unknown protocol version %d", result[0]) - return - } - expectedOp := msg[1] | 0x80 - if result[1] != expectedOp { - err = fmt.Errorf("Unexpected opcode %d. Expected %d", result[1], expectedOp) - return - } - resultCode := readNetworkOrderUint16(result[2:4]) - if resultCode != 0 { - err = fmt.Errorf("Non-zero result code %d", resultCode) - return - } - // If we got here the RPC is good. - return - } - err = fmt.Errorf("Timed out trying to contact gateway") - return -} - -func writeNetworkOrderUint16(buf []byte, d uint16) { - buf[0] = byte(d >> 8) - buf[1] = byte(d) -} - -func writeNetworkOrderUint32(buf []byte, d uint32) { - buf[0] = byte(d >> 24) - buf[1] = byte(d >> 16) - buf[2] = byte(d >> 8) - buf[3] = byte(d) -} - -func readNetworkOrderUint16(buf []byte) uint16 { - return (uint16(buf[0]) << 8) | uint16(buf[1]) -} - -func readNetworkOrderUint32(buf []byte) uint32 { - return (uint32(buf[0]) << 24) | (uint32(buf[1]) << 16) | (uint32(buf[2]) << 8) | uint32(buf[3]) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.gitignore b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.gitignore deleted file mode 100644 index 00a069958..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.gitignore +++ /dev/null @@ -1 +0,0 @@ -example/closer diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.travis.yml b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.travis.yml deleted file mode 100644 index 5828fd674..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.3 - - 1.4 - - release - - tip - -script: - - go test -v ./... - # - go test -race -cpu=5 ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Godeps.json b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Godeps.json deleted file mode 100644 index 11479d2d9..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Godeps.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "ImportPath": "github.com/jbenet/go-peerstream", - "GoVersion": "go1.4.2", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/docker/spdystream", - "Rev": "b2c3287865f3ad6aa22821ddb7b4692b896ac207" - }, - { - "ImportPath": "github.com/hashicorp/yamux", - "Rev": "b2e55852ddaf823a85c67f798080eb7d08acd71d" - }, - { - "ImportPath": "github.com/inconshreveable/muxado", - "Rev": "f693c7e88ba316d1a0ae3e205e22a01aa3ec2848" - }, - { - "ImportPath": "github.com/jbenet/go-stream-muxer", - "Rev": "e2e261765847234749629e0190fef193a4548303" - }, - { - "ImportPath": "github.com/jbenet/go-temp-err-catcher", - "Rev": "aac704a3f4f27190b4ccc05f303a4931fd1241ff" - }, - { - "ImportPath": "github.com/whyrusleeping/go-multiplex", - "Rev": "474b9aebeb391746f304ddf7c764a5da12319857" - }, - { - "ImportPath": "github.com/whyrusleeping/go-multistream", - "Rev": "08e8f9c9f5665ed0c63ffde4fa5ef1d5fb3d516d" - } - ] -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Readme b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Readme deleted file mode 100644 index 4cdaa53d5..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/LICENSE b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/LICENSE deleted file mode 100644 index c7386b3c9..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Juan Batiz-Benet - -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. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Makefile b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Makefile deleted file mode 100644 index f15fcaa68..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -godep: - go get github.com/tools/godep - -vendor: godep - godep save -r ./... - -build: - go build ./... - -test: - go test ./... - -test_race: - go test -race -cpu 5 ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/README.md b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/README.md deleted file mode 100644 index 04ec1152f..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/README.md +++ /dev/null @@ -1,148 +0,0 @@ -# go-peerstream p2p multi-multixplexing - -Package peerstream is a peer-to-peer networking library that multiplexes -connections to many hosts. It tried to simplify the complexity of: - -* accepting incoming connections over **multiple** listeners -* dialing outgoing connections over **multiple** transports -* multiplexing **multiple** connections per-peer -* multiplexing **multiple** different servers or protocols -* handling backpressure correctly -* handling stream multiplexing (we use SPDY, but maybe QUIC some day) -* providing a **simple** interface to the user - -### Godoc: https://godoc.org/github.com/jbenet/go-peerstream - ---- - -See this working [example/example.go](example/example): - -```Go -package main - -import ( - "fmt" - "io" - "net" - "os" - - ps "github.com/jbenet/go-peerstream" -) - -func main() { - // create a new Swarm - swarm := ps.NewSwarm() - defer swarm.Close() - - // tell swarm what to do with a new incoming streams. - // EchoHandler just echos back anything they write. - swarm.SetStreamHandler(ps.EchoHandler) - - // Okay, let's try listening on some transports - l1, err := net.Listen("tcp", "localhost:8001") - if err != nil { - panic(err) - } - - l2, err := net.Listen("tcp", "localhost:8002") - if err != nil { - panic(err) - } - - // tell swarm to accept incoming connections on these - // listeners. Swarm will start accepting new connections. - if err := swarm.AddListener(l1); err != nil { - panic(err) - } - if err := swarm.AddListener(l2); err != nil { - panic(err) - } - - // ok, let's try some outgoing connections - nc1, err := net.Dial("tcp", "localhost:8001") - if err != nil { - panic(err) - } - - nc2, err := net.Dial("tcp", "localhost:8002") - if err != nil { - panic(err) - } - - // add them to the swarm - c1, err := swarm.AddConn(nc1) - if err != nil { - panic(err) - } - c2, err := swarm.AddConn(nc2) - if err != nil { - panic(err) - } - - // Swarm treats listeners as sources of new connections and does - // not distinguish between outgoing or incoming connections. - // It provides the net.Conn to the StreamHandler so you can - // distinguish between them however you wish. - - // now let's try opening some streams! - // You can specify what connection you want to use - s1, err := swarm.NewStreamWithConn(c1) - if err != nil { - panic(err) - } - - // Or, you can specify a SelectConn function that picks between all - // (it calls NewStreamWithConn underneath the hood) - s2, err := swarm.NewStreamSelectConn(func(conns []*ps.Conn) *ps.Conn { - if len(conns) > 0 { - return conns[0] - } - return nil - }) - if err != nil { - panic(err) - } - - // Or, you can bind connections to ConnGroup ids. You can bind a conn to - // multiple groups. And, if conn wasn't in swarm, it calls swarm.AddConn. - // You can use any Go `KeyType` as a group A `KeyType` as in maps...) - swarm.AddConnToGroup(c2, 1) - - // And then use that group to select a connection. Swarm will use any - // connection it finds in that group, using a SelectConn you can rebind: - // swarm.SetGroupSelectConn(1, SelectConn) - // swarm.SetDegaultGroupSelectConn(SelectConn) - s3, err := swarm.NewStreamWithGroup(1) - if err != nil { - panic(err) - } - - // Why groups? It's because with many connections, and many transports, - // and many Servers (or Protocols), we can use the Swarm to associate - // a different StreamHandlers per group, and to let us create NewStreams - // on a given group. - - // Ok, we have streams. now what. Use them! Our Streams are basically - // streams from github.com/docker/spdystream, so they work the same - // way: - - for i, stream := range []ps.Stream{s1, s2, s3} { - stream.Wait() - str := "stream %d ready:" - fmt.Fprintf(stream, str, i) - - buf := make([]byte, len(str)) - stream.Read(buf) - fmt.Println(string(buf)) - } - - go io.Copy(os.Stdout, s1) - go io.Copy(os.Stdout, s2) - go io.Copy(os.Stdout, s3) - io.Copy(io.MultiWriter(s1, s2, s3), os.Stdin) -} - -func log(s string) { - fmt.Fprintf(os.Stderr, s+"\n") -} -``` diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/conn.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/conn.go deleted file mode 100644 index c4d9d3725..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/conn.go +++ /dev/null @@ -1,311 +0,0 @@ -package peerstream - -import ( - "errors" - "fmt" - "net" - "sync" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -// ConnHandler is a function which receives a Conn. It allows -// clients to set a function to receive newly accepted -// connections. It works like StreamHandler, but is usually -// less useful than usual as most services will only use -// Streams. It is safe to pass or store the *Conn elsewhere. -// Note: the ConnHandler is called sequentially, so spawn -// goroutines or pass the Conn. See EchoHandler. -type ConnHandler func(s *Conn) - -// SelectConn selects a connection out of list. It allows -// delegation of decision making to clients. Clients can -// make SelectConn functons that check things connection -// qualities -- like latency andbandwidth -- or pick from -// a logical set of connections. -type SelectConn func([]*Conn) *Conn - -// ErrInvalidConnSelected signals that a connection selected -// with a SelectConn function is invalid. This may be due to -// the Conn not being part of the original set given to the -// function, or the value being nil. -var ErrInvalidConnSelected = errors.New("invalid selected connection") - -// ErrNoConnections signals that no connections are available -var ErrNoConnections = errors.New("no connections") - -// Conn is a Swarm-associated connection. -type Conn struct { - smuxConn smux.Conn - netConn net.Conn // underlying connection - - swarm *Swarm - groups groupSet - - streams map[*Stream]struct{} - streamLock sync.RWMutex - - closed bool - closeLock sync.Mutex - - closing bool - closingLock sync.Mutex -} - -func newConn(nconn net.Conn, tconn smux.Conn, s *Swarm) *Conn { - return &Conn{ - netConn: nconn, - smuxConn: tconn, - swarm: s, - groups: groupSet{m: make(map[Group]struct{})}, - streams: make(map[*Stream]struct{}), - } -} - -// String returns a string representation of the Conn -func (c *Conn) String() string { - c.streamLock.RLock() - ls := len(c.streams) - c.streamLock.RUnlock() - f := " %s>" - return fmt.Sprintf(f, ls, c.netConn.LocalAddr(), c.netConn.RemoteAddr()) -} - -// Swarm returns the Swarm associated with this Conn -func (c *Conn) Swarm() *Swarm { - return c.swarm -} - -// NetConn returns the underlying net.Conn -func (c *Conn) NetConn() net.Conn { - return c.netConn -} - -// Conn returns the underlying transport Connection we use -// Warning: modifying this object is undefined. -func (c *Conn) Conn() smux.Conn { - return c.smuxConn -} - -// Groups returns the Groups this Conn belongs to -func (c *Conn) Groups() []Group { - return c.groups.Groups() -} - -// InGroup returns whether this Conn belongs to a Group -func (c *Conn) InGroup(g Group) bool { - return c.groups.Has(g) -} - -// AddGroup assigns given Group to Conn -func (c *Conn) AddGroup(g Group) { - c.groups.Add(g) -} - -// Stream returns a stream associated with this Conn -func (c *Conn) NewStream() (*Stream, error) { - return c.swarm.NewStreamWithConn(c) -} - -func (c *Conn) Streams() []*Stream { - c.streamLock.RLock() - defer c.streamLock.RUnlock() - - streams := make([]*Stream, 0, len(c.streams)) - for s := range c.streams { - streams = append(streams, s) - } - return streams -} - -// GoClose spawns off a goroutine to close the connection iff the connection is -// not already being closed and returns immediately -func (c *Conn) GoClose() { - c.closingLock.Lock() - defer c.closingLock.Unlock() - if c.closing { - return - } - c.closing = true - - go c.Close() -} - -// Close closes this connection -func (c *Conn) Close() error { - c.closeLock.Lock() - defer c.closeLock.Unlock() - if c.closed == true { - return nil - } - - c.closingLock.Lock() - c.closing = true - c.closingLock.Unlock() - - c.closed = true - - // close streams - streams := c.Streams() - for _, s := range streams { - s.Close() - } - - // close underlying connection - c.swarm.removeConn(c) - err := c.smuxConn.Close() - c.swarm.notifyAll(func(n Notifiee) { - n.Disconnected(c) - }) - return err -} - -// ConnsWithGroup narrows down a set of connections to those in a given group. -func ConnsWithGroup(g Group, conns []*Conn) []*Conn { - var out []*Conn - for _, c := range conns { - if c.InGroup(g) { - out = append(out, c) - } - } - return out -} - -func ConnInConns(c1 *Conn, conns []*Conn) bool { - for _, c2 := range conns { - if c2 == c1 { - return true - } - } - return false -} - -// ------------------------------------------------------------------ -// All the connection setup logic here, in one place. -// these are mostly *Swarm methods, but i wanted a less-crowded place -// for them. -// ------------------------------------------------------------------ - -// addConn is the internal version of AddConn. we need the server bool -// as spdystream requires it. -func (s *Swarm) addConn(netConn net.Conn, isServer bool) (*Conn, error) { - c, err := s.setupConn(netConn, isServer) - if err != nil { - return nil, err - } - - s.ConnHandler()(c) - - // go listen for incoming streams on this connection - go c.smuxConn.Serve(func(ss smux.Stream) { - // log.Printf("accepted stream %d from %s\n", ssS.Identifier(), netConn.RemoteAddr()) - stream := s.setupStream(ss, c) - s.StreamHandler()(stream) // call our handler - }) - - s.notifyAll(func(n Notifiee) { - n.Connected(c) - }) - return c, nil -} - -// setupConn adds the relevant connection to the map, first checking if it -// was already there. -func (s *Swarm) setupConn(netConn net.Conn, isServer bool) (*Conn, error) { - if netConn == nil { - return nil, errors.New("nil conn") - } - - // first, check if we already have it, to avoid constructing it - // if it is already there - s.connLock.Lock() - for c := range s.conns { - if c.netConn == netConn { - s.connLock.Unlock() - return c, nil - } - } - s.connLock.Unlock() - // construct the connection without hanging onto the lock - // (as there could be deadlock if so.) - - // create a new spdystream connection - ssConn, err := s.transport.NewConn(netConn, isServer) - if err != nil { - return nil, err - } - - // take the lock to add it to the map. - s.connLock.Lock() - defer s.connLock.Unlock() - - // check for it again as it may have been added already. (TOCTTOU) - for c := range s.conns { - if c.netConn == netConn { - return c, nil - } - } - - // add the connection - c := newConn(netConn, ssConn, s) - s.conns[c] = struct{}{} - return c, nil -} - -// createStream is the internal function that creates a new stream. assumes -// all validation has happened. -func (s *Swarm) createStream(c *Conn) (*Stream, error) { - - // Create a new smux.Stream - smuxStream, err := c.smuxConn.OpenStream() - if err != nil { - return nil, err - } - - return s.setupStream(smuxStream, c), nil -} - -// newStream is the internal function that creates a new stream. assumes -// all validation has happened. -func (s *Swarm) setupStream(smuxStream smux.Stream, c *Conn) *Stream { - - // create a new stream - stream := newStream(smuxStream, c) - - // add it to our streams maps - s.streamLock.Lock() - c.streamLock.Lock() - s.streams[stream] = struct{}{} - c.streams[stream] = struct{}{} - s.streamLock.Unlock() - c.streamLock.Unlock() - - s.notifyAll(func(n Notifiee) { - n.OpenedStream(stream) - }) - return stream -} - -func (s *Swarm) removeStream(stream *Stream) error { - - // remove from our maps - s.streamLock.Lock() - stream.conn.streamLock.Lock() - delete(s.streams, stream) - delete(stream.conn.streams, stream) - s.streamLock.Unlock() - stream.conn.streamLock.Unlock() - - err := stream.smuxStream.Close() - s.notifyAll(func(n Notifiee) { - n.ClosedStream(stream) - }) - return err -} - -func (s *Swarm) removeConn(conn *Conn) { - // remove from our maps - s.connLock.Lock() - delete(s.conns, conn) - s.connLock.Unlock() -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/doc.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/doc.go deleted file mode 100644 index 502a04d28..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package peerstream is a peer-to-peer networking library that multiplexes -// connections to many hosts. It tried to simplify the complexity of: -// -// * accepting incoming connections over **multiple** listeners -// * dialing outgoing connections over **multiple** transports -// * multiplexing **multiple** connections per-peer -// * multiplexing **multiple** different servers or protocols -// * handling backpressure correctly -// * handling stream multiplexing (we use SPDY, but maybe QUIC some day) -// * providing a **simple** interface to the user -// -package peerstream diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/.gitignore b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/.gitignore deleted file mode 100644 index 33a9488b1..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -example diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/blockhandler/blockhandler.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/blockhandler/blockhandler.go deleted file mode 100644 index 4a7036583..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/blockhandler/blockhandler.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "net" - "os" - "time" - - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - spdy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream" -) - -func die(err error) { - fmt.Fprintf(os.Stderr, "error: %s\n") - os.Exit(1) -} - -func main() { - // create a new Swarm - swarm := ps.NewSwarm(spdy.Transport) - defer swarm.Close() - - // tell swarm what to do with a new incoming streams. - // EchoHandler just echos back anything they write. - swarm.SetStreamHandler(ps.EchoHandler) - - l, err := net.Listen("tcp", "localhost:8001") - if err != nil { - die(err) - } - - if _, err := swarm.AddListener(l); err != nil { - die(err) - } - - nc, err := net.Dial("tcp", "localhost:8001") - if err != nil { - die(err) - } - - c, err := swarm.AddConn(nc) - if err != nil { - die(err) - } - - nRcvStream := 0 - bio := bufio.NewReader(os.Stdin) - swarm.SetStreamHandler(func(s *ps.Stream) { - log("handling new stream %d", nRcvStream) - nRcvStream++ - - line, err := bio.ReadString('\n') - if err != nil { - die(err) - } - _ = line - // line = "read: " + line - // s.Write([]byte(line)) - s.Close() - }) - - nSndStream := 0 - for { - <-time.After(200 * time.Millisecond) - _, err := swarm.NewStreamWithConn(c) - if err != nil { - die(err) - } - log("sender got new stream %d", nSndStream) - nSndStream++ - } -} - -func log(s string, ifs ...interface{}) { - fmt.Fprintf(os.Stderr, s+"\n", ifs...) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example.go deleted file mode 100644 index 9149f5a9b..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/example/example.go +++ /dev/null @@ -1,140 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net" - "os" - - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - spdy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream" -) - -func main() { - - log("creating a new swarm with spdystream transport") // create a new Swarm - swarm := ps.NewSwarm(spdy.Transport) - defer swarm.Close() - - // tell swarm what to do with a new incoming streams. - // EchoHandler just echos back anything they write. - log("setup EchoHandler") - swarm.SetStreamHandler(ps.EchoHandler) - - // Okay, let's try listening on some transports - log("listening at localhost:8001") - l1, err := net.Listen("tcp", "localhost:8001") - if err != nil { - panic(err) - } - - log("listening at localhost:8002") - l2, err := net.Listen("tcp", "localhost:8002") - if err != nil { - panic(err) - } - - // tell swarm to accept incoming connections on these - // listeners. Swarm will start accepting new connections. - if _, err := swarm.AddListener(l1); err != nil { - panic(err) - } - if _, err := swarm.AddListener(l2); err != nil { - panic(err) - } - - // ok, let's try some outgoing connections - log("dialing localhost:8001") - nc1, err := net.Dial("tcp", "localhost:8001") - if err != nil { - panic(err) - } - - log("dialing localhost:8002") - nc2, err := net.Dial("tcp", "localhost:8002") - if err != nil { - panic(err) - } - - // add them to the swarm - c1, err := swarm.AddConn(nc1) - if err != nil { - panic(err) - } - c2, err := swarm.AddConn(nc2) - if err != nil { - panic(err) - } - - // Swarm treats listeners as sources of new connections and does - // not distinguish between outgoing or incoming connections. - // It provides the net.Conn to the StreamHandler so you can - // distinguish between them however you wish. - - // now let's try opening some streams! - // You can specify what connection you want to use - log("opening stream with NewStreamWithConn(c1)") - s1, err := swarm.NewStreamWithConn(c1) - if err != nil { - panic(err) - } - - // Or, you can specify a SelectConn function that picks between all - // (it calls NewStreamWithConn underneath the hood) - log("opening stream with NewStreamSelectConn(.)") - s2, err := swarm.NewStreamSelectConn(func(conns []*ps.Conn) *ps.Conn { - if len(conns) > 0 { - return conns[0] - } - return nil - }) - if err != nil { - panic(err) - } - - // Or, you can bind connections to ConnGroup ids. You can bind a conn to - // multiple groups. And, if conn wasn't in swarm, it calls swarm.AddConn. - // You can use any Go `KeyType` as a group A `KeyType` as in maps...) - swarm.AddConnToGroup(c2, 1) - - // And then use that group to select a connection. Swarm will use any - // connection it finds in that group, using a SelectConn you can rebind: - // swarm.SetGroupSelectConn(1, SelectConn) - // swarm.SetDegaultGroupSelectConn(SelectConn) - log("opening stream with NewStreamWithGroup(1)") - s3, err := swarm.NewStreamWithGroup(1) - if err != nil { - panic(err) - } - - // Why groups? It's because with many connections, and many transports, - // and many Servers (or Protocols), we can use the Swarm to associate - // a different StreamHandlers per group, and to let us create NewStreams - // on a given group. - - // Ok, we have streams. now what. Use them! Our Streams are basically - // streams from github.com/docker/spdystream, so they work the same - // way: - - log("preparing the streams") - for i, stream := range []*ps.Stream{s1, s2, s3} { - str := "stream %d ready:" - fmt.Fprintf(stream, str, i) - - buf := make([]byte, len(str)) - log(fmt.Sprintf("reading from stream %d", i)) - stream.Read(buf) - fmt.Println(string(buf)) - } - - log("let's test the streams") - log("enter some text below:\n") - go io.Copy(os.Stdout, s1) - go io.Copy(os.Stdout, s2) - go io.Copy(os.Stdout, s3) - io.Copy(io.MultiWriter(s1, s2, s3), os.Stdin) -} - -func log(s string) { - fmt.Fprintf(os.Stderr, s+"\n") -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/group.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/group.go deleted file mode 100644 index 8e08e7ab7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/group.go +++ /dev/null @@ -1,92 +0,0 @@ -package peerstream - -import ( - "errors" - "sync" - "unsafe" -) - -// ErrGroupNotFound signals no such group exists -var ErrGroupNotFound = errors.New("group not found") - -// Group is an object used to associate a group of -// Streams, Connections, and Listeners. It can be anything, -// it is meant to work like a KeyType in maps -type Group interface{} - -// Groupable is an interface for a set of objects that can -// be assigned groups: Streams, Connections, and Listeners. -// Objects inherit groups (e.g. a Stream inherits the groups -// of its parent Connection, and in turn that of its Listener). -type Groupable interface { - // Groups returns the groups this object belongs to - Groups() []Group - - // InGroup returns whether this object belongs to a Group - InGroup(g Group) bool - - // AddGroup adds this object to a group - AddGroup(g Group) -} - -// groupSet is a struct designed to be embedded and -// give things group memebership -type groupSet struct { - m map[Group]struct{} - sync.RWMutex -} - -func (gs *groupSet) Add(g Group) { - gs.Lock() - defer gs.Unlock() - gs.m[g] = struct{}{} -} - -func (gs *groupSet) Remove(g Group) { - gs.Lock() - defer gs.Unlock() - delete(gs.m, g) -} - -func (gs *groupSet) Has(g Group) bool { - gs.RLock() - defer gs.RUnlock() - _, ok := gs.m[g] - return ok -} - -func (gs *groupSet) Groups() []Group { - gs.RLock() - defer gs.RUnlock() - - out := make([]Group, 0, len(gs.m)) - for k := range gs.m { - out = append(out, k) - } - return out -} - -// AddSet adds all elements in another set. -func (gs *groupSet) AddSet(gs2 *groupSet) { - // acquire locks in order - p1 := uintptr(unsafe.Pointer(gs)) - p2 := uintptr(unsafe.Pointer(gs2)) - switch { - case p1 < p2: - gs.Lock() - gs2.RLock() - defer gs.Unlock() - defer gs2.RUnlock() - case p1 > p2: - gs2.Lock() - gs.Lock() - defer gs2.Unlock() - defer gs.Unlock() - default: - return // they're the same! - } - - for g := range gs2.m { - gs.m[g] = struct{}{} - } -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/handlers.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/handlers.go deleted file mode 100644 index 79290fd16..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/handlers.go +++ /dev/null @@ -1,29 +0,0 @@ -package peerstream - -import ( - "io" - "math/rand" -) - -var SelectRandomConn = func(conns []*Conn) *Conn { - if len(conns) == 0 { - return nil - } - - return conns[rand.Intn(len(conns))] -} - -func EchoHandler(s *Stream) { - go func() { - io.Copy(s, s) - s.Close() - }() -} - -func CloseHandler(s *Stream) { - s.Close() -} - -func NoOpStreamHandler(s *Stream) {} - -func NoOpConnHandler(c *Conn) {} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/listener.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/listener.go deleted file mode 100644 index 2fbc7c77c..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/listener.go +++ /dev/null @@ -1,163 +0,0 @@ -package peerstream - -import ( - "errors" - "fmt" - "net" - "sync" - - tec "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher" -) - -// AcceptConcurrency is how many connections can simultaneously be -// in process of being accepted. Handshakes can sometimes occur as -// part of this process, so it may take some time. It is imporant to -// rate limit lest a malicious influx of connections would cause our -// node to consume all its resources accepting new connections. -var AcceptConcurrency = 200 - -type Listener struct { - netList net.Listener - groups groupSet - swarm *Swarm - - acceptErr chan error -} - -func newListener(nl net.Listener, s *Swarm) *Listener { - return &Listener{ - netList: nl, - swarm: s, - acceptErr: make(chan error, 10), - } -} - -// String returns a string representation of the Listener -func (l *Listener) String() string { - f := "" - return fmt.Sprintf(f, l.netList.Addr()) -} - -// NetListener is the underlying net.Listener -func (l *Listener) NetListener() net.Listener { - return l.netList -} - -// Groups returns the groups this Listener belongs to -func (l *Listener) Groups() []Group { - return l.groups.Groups() -} - -// InGroup returns whether this Listener belongs to a Group -func (l *Listener) InGroup(g Group) bool { - return l.groups.Has(g) -} - -// AddGroup assigns given Group to Listener -func (l *Listener) AddGroup(g Group) { - l.groups.Add(g) -} - -// ListenersWithGroup narrows down a set of listeners to those in given group. -func ListenersWithGroup(g Group, ls []*Listener) []*Listener { - var out []*Listener - for _, l := range ls { - if l.InGroup(g) { - out = append(out, l) - } - } - return out -} - -// accept continously accepts incoming connections and -// adds them to the listener's Swarm. is is meant to be -// run in a goroutine. -// TODO: add rate limiting -func (l *Listener) accept() { - var wg sync.WaitGroup - defer func() { - wg.Wait() // must happen before teardown - l.teardown() - }() - - // catching the error here is odd. doing what net/http does: - // http://golang.org/src/net/http/server.go?s=51504:51550#L1728 - // Using the lib: https://godoc.org/github.com/jbenet/go-temp-err-catcher - var catcher tec.TempErrCatcher - - // rate limit concurrency - limit := make(chan struct{}, AcceptConcurrency) - - // loop forever accepting connections - for { - conn, err := l.netList.Accept() - if err != nil { - if catcher.IsTemporary(err) { - continue - } - l.acceptErr <- fmt.Errorf("peerstream listener failed: %s", err) - return // ok, problems. bail. - } - - // add conn to swarm and listen for incoming streams - // do this in a goroutine to avoid blocking the Accept loop. - // note that this does not rate limit accepts. - limit <- struct{}{} // sema down - wg.Add(1) - go func(conn net.Conn) { - defer func() { <-limit }() // sema up - defer wg.Done() - - conn2, err := l.swarm.addConn(conn, true) - if err != nil { - l.acceptErr <- err - return - } - conn2.groups.AddSet(&l.groups) // add out groups - }(conn) - } -} - -// AcceptError returns the error that we **might** on listener close -func (l *Listener) AcceptErrors() <-chan error { - return l.acceptErr -} - -func (l *Listener) teardown() { - // in case we exit from network errors (accept fails) but - // (a) client doesn't call Close, and (b) listener remains open) - l.netList.Close() - - close(l.acceptErr) - - // remove self from swarm - l.swarm.listenerLock.Lock() - delete(l.swarm.listeners, l) - l.swarm.listenerLock.Unlock() -} - -func (l *Listener) Close() error { - return l.netList.Close() -} - -// addListener is the internal version of AddListener. -func (s *Swarm) addListener(nl net.Listener) (*Listener, error) { - if nl == nil { - return nil, errors.New("nil listener") - } - - s.listenerLock.Lock() - defer s.listenerLock.Unlock() - - // first, check if we already have it... - for l := range s.listeners { - if l.netList == nl { - return l, nil - } - } - - l := newListener(nl, s) - s.listeners[l] = struct{}{} - go l.accept() - return l, nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/hack.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/hack.go deleted file mode 100644 index c1af4e81b..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/hack.go +++ /dev/null @@ -1,15 +0,0 @@ -package muxtest - -import ( - multiplex "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex" - multistream "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream" - muxado "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado" - spdy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream" - yamux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux" -) - -var _ = multiplex.DefaultTransport -var _ = multistream.NewTransport -var _ = muxado.Transport -var _ = spdy.Transport -var _ = yamux.DefaultTransport diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/mux_test.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/mux_test.go deleted file mode 100644 index 811c89d29..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/mux_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package muxtest - -import ( - "testing" - - multiplex "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex" - multistream "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream" - muxado "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado" - spdy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream" - yamux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux" -) - -func TestYamuxTransport(t *testing.T) { - SubtestAll(t, yamux.DefaultTransport) -} - -func TestSpdyStreamTransport(t *testing.T) { - SubtestAll(t, spdy.Transport) -} - -func TestMultiplexTransport(t *testing.T) { - SubtestAll(t, multiplex.DefaultTransport) -} - -func TestMuxadoTransport(t *testing.T) { - SubtestAll(t, muxado.Transport) -} - -func TestMultistreamTransport(t *testing.T) { - SubtestAll(t, multistream.NewTransport()) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/muxt.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/muxt.go deleted file mode 100644 index dd3342a0d..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/muxtest/muxt.go +++ /dev/null @@ -1,422 +0,0 @@ -package muxtest - -import ( - "bytes" - crand "crypto/rand" - "fmt" - "io" - mrand "math/rand" - "net" - "os" - "reflect" - "runtime" - "sync" - "testing" - - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -var randomness []byte -var nextPort = 20000 -var verbose = false - -func init() { - // read 1MB of randomness - randomness = make([]byte, 1<<20) - if _, err := crand.Read(randomness); err != nil { - panic(err) - } -} - -func randBuf(size int) []byte { - n := len(randomness) - size - if size < 1 { - panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness))) - } - - start := mrand.Intn(n) - return randomness[start : start+size] -} - -func checkErr(t *testing.T, err error) { - if err != nil { - t.Fatal(err) - } -} - -func log(s string, v ...interface{}) { - if verbose { - fmt.Fprintf(os.Stderr, "> "+s+"\n", v...) - } -} - -type echoSetup struct { - swarm *ps.Swarm - conns []*ps.Conn -} - -func singleConn(t *testing.T, tr smux.Transport) echoSetup { - swarm := ps.NewSwarm(tr) - swarm.SetStreamHandler(func(s *ps.Stream) { - defer s.Close() - log("accepted stream") - io.Copy(s, s) // echo everything - log("closing stream") - }) - - log("listening at %s", "localhost:0") - l, err := net.Listen("tcp", "localhost:0") - checkErr(t, err) - - _, err = swarm.AddListener(l) - checkErr(t, err) - - log("dialing to %s", l.Addr()) - nc1, err := net.Dial("tcp", l.Addr().String()) - checkErr(t, err) - - c1, err := swarm.AddConn(nc1) - checkErr(t, err) - - return echoSetup{ - swarm: swarm, - conns: []*ps.Conn{c1}, - } -} - -func makeSwarm(t *testing.T, tr smux.Transport, nListeners int) *ps.Swarm { - swarm := ps.NewSwarm(tr) - swarm.SetStreamHandler(func(s *ps.Stream) { - defer s.Close() - log("accepted stream") - io.Copy(s, s) // echo everything - log("closing stream") - }) - - for i := 0; i < nListeners; i++ { - log("%p listening at %s", swarm, "localhost:0") - l, err := net.Listen("tcp", "localhost:0") - checkErr(t, err) - _, err = swarm.AddListener(l) - checkErr(t, err) - } - - return swarm -} - -func makeSwarms(t *testing.T, tr smux.Transport, nSwarms, nListeners int) []*ps.Swarm { - swarms := make([]*ps.Swarm, nSwarms) - for i := 0; i < nSwarms; i++ { - swarms[i] = makeSwarm(t, tr, nListeners) - } - return swarms -} - -func SubtestConstructSwarm(t *testing.T, tr smux.Transport) { - ps.NewSwarm(tr) -} - -func SubtestSimpleWrite(t *testing.T, tr smux.Transport) { - swarm := ps.NewSwarm(tr) - defer swarm.Close() - - piper, pipew := io.Pipe() - swarm.SetStreamHandler(func(s *ps.Stream) { - defer s.Close() - log("accepted stream") - w := io.MultiWriter(s, pipew) - io.Copy(w, s) // echo everything and write it to pipew - log("closing stream") - }) - - log("listening at %s", "localhost:0") - l, err := net.Listen("tcp", "localhost:0") - checkErr(t, err) - - _, err = swarm.AddListener(l) - checkErr(t, err) - - log("dialing to %s", l.Addr().String()) - nc1, err := net.Dial("tcp", l.Addr().String()) - checkErr(t, err) - - c1, err := swarm.AddConn(nc1) - checkErr(t, err) - defer c1.Close() - - log("creating stream") - s1, err := c1.NewStream() - checkErr(t, err) - defer s1.Close() - - buf1 := randBuf(4096) - log("writing %d bytes to stream", len(buf1)) - _, err = s1.Write(buf1) - checkErr(t, err) - - buf2 := make([]byte, len(buf1)) - log("reading %d bytes from stream (echoed)", len(buf2)) - _, err = s1.Read(buf2) - checkErr(t, err) - if string(buf2) != string(buf1) { - t.Error("buf1 and buf2 not equal: %s != %s", string(buf1), string(buf2)) - } - - buf3 := make([]byte, len(buf1)) - log("reading %d bytes from pipe (tee)", len(buf3)) - _, err = piper.Read(buf3) - checkErr(t, err) - if string(buf3) != string(buf1) { - t.Error("buf1 and buf3 not equal: %s != %s", string(buf1), string(buf3)) - } -} - -func SubtestSimpleWrite100msgs(t *testing.T, tr smux.Transport) { - - msgs := 100 - msgsize := 1 << 19 - es := singleConn(t, tr) - defer es.swarm.Close() - - log("creating stream") - stream, err := es.conns[0].NewStream() - checkErr(t, err) - - bufs := make(chan []byte, msgs) - var wg sync.WaitGroup - - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - buf := randBuf(msgsize) - bufs <- buf - log("writing %d bytes (message %d/%d #%x)", len(buf), i, msgs, buf[:3]) - if _, err := stream.Write(buf); err != nil { - t.Error(fmt.Errorf("stream.Write(buf): %s", err)) - continue - } - } - close(bufs) - }() - - wg.Add(1) - go func() { - defer wg.Done() - - buf2 := make([]byte, msgsize) - i := 0 - for buf1 := range bufs { - log("reading %d bytes (message %d/%d #%x)", len(buf1), i, msgs, buf1[:3]) - i++ - - if _, err := io.ReadFull(stream, buf2); err != nil { - t.Error(fmt.Errorf("readFull(stream, buf2): %s", err)) - continue - } - if !bytes.Equal(buf1, buf2) { - t.Error(fmt.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])) - } - } - }() - - wg.Wait() -} - -func SubtestStressNSwarmNConnNStreamNMsg(t *testing.T, tr smux.Transport, nSwarm, nConn, nStream, nMsg int) { - - msgsize := 1 << 11 - - rateLimitN := 5000 - rateLimitChan := make(chan struct{}, rateLimitN) // max of 5k funcs. - for i := 0; i < rateLimitN; i++ { - rateLimitChan <- struct{}{} - } - - rateLimit := func(f func()) { - <-rateLimitChan - f() - rateLimitChan <- struct{}{} - } - - writeStream := func(s *ps.Stream, bufs chan<- []byte) { - log("writeStream %p, %d nMsg", s, nMsg) - - for i := 0; i < nMsg; i++ { - buf := randBuf(msgsize) - bufs <- buf - log("%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, nMsg, buf[:3]) - if _, err := s.Write(buf); err != nil { - t.Error(fmt.Errorf("s.Write(buf): %s", err)) - continue - } - } - } - - readStream := func(s *ps.Stream, bufs <-chan []byte) { - log("readStream %p, %d nMsg", s, nMsg) - - buf2 := make([]byte, msgsize) - i := 0 - for buf1 := range bufs { - i++ - log("%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, nMsg, buf1[:3]) - - if _, err := io.ReadFull(s, buf2); err != nil { - log("%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, nMsg, buf1[:3]) - t.Error(fmt.Errorf("io.ReadFull(s, buf2): %s", err)) - continue - } - if !bytes.Equal(buf1, buf2) { - t.Error(fmt.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])) - } - } - } - - openStreamAndRW := func(c *ps.Conn) { - log("openStreamAndRW %p, %d nMsg", c, nMsg) - - s, err := c.NewStream() - if err != nil { - t.Error(fmt.Errorf("Failed to create NewStream: %s", err)) - return - } - - bufs := make(chan []byte, nMsg) - go func() { - writeStream(s, bufs) - close(bufs) - }() - - readStream(s, bufs) - s.Close() - } - - openConnAndRW := func(a, b *ps.Swarm) { - log("openConnAndRW %p -> %p, %d nStream", a, b, nConn) - - ls := b.Listeners() - l := ls[mrand.Intn(len(ls))] - nl := l.NetListener() - nla := nl.Addr() - - nc, err := net.Dial(nla.Network(), nla.String()) - if err != nil { - t.Fatal(fmt.Errorf("net.Dial(%s, %s): %s", nla.Network(), nla.String(), err)) - return - } - - c, err := a.AddConn(nc) - if err != nil { - t.Fatal(fmt.Errorf("a.AddConn(%s <--> %s): %s", nc.LocalAddr(), nc.RemoteAddr(), err)) - return - } - - var wg sync.WaitGroup - for i := 0; i < nStream; i++ { - wg.Add(1) - go rateLimit(func() { - defer wg.Done() - openStreamAndRW(c) - }) - } - wg.Wait() - c.Close() - } - - openConnsAndRW := func(a, b *ps.Swarm) { - log("openConnsAndRW %p -> %p, %d conns", a, b, nConn) - - var wg sync.WaitGroup - for i := 0; i < nConn; i++ { - wg.Add(1) - go rateLimit(func() { - defer wg.Done() - openConnAndRW(a, b) - }) - } - wg.Wait() - } - - connectSwarmsAndRW := func(swarms []*ps.Swarm) { - log("connectSwarmsAndRW %d swarms", len(swarms)) - - var wg sync.WaitGroup - for _, a := range swarms { - for _, b := range swarms { - wg.Add(1) - a := a // race - b := b // race - go rateLimit(func() { - defer wg.Done() - openConnsAndRW(a, b) - }) - } - } - wg.Wait() - } - - swarms := makeSwarms(t, tr, nSwarm, 3) // 3 listeners per swarm. - connectSwarmsAndRW(swarms) - for _, s := range swarms { - s.Close() - } - -} - -func SubtestStress1Swarm1Conn1Stream1Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 1, 1, 1, 1) -} - -func SubtestStress1Swarm1Conn1Stream100Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 1, 1, 1, 100) -} - -func SubtestStress1Swarm1Conn100Stream100Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 1, 1, 100, 100) -} - -func SubtestStress1Swarm10Conn50Stream50Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 1, 10, 50, 50) -} - -func SubtestStress5Swarm2Conn20Stream20Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 5, 2, 20, 20) -} - -func SubtestStress10Swarm2Conn100Stream100Msg(t *testing.T, tr smux.Transport) { - SubtestStressNSwarmNConnNStreamNMsg(t, tr, 10, 2, 100, 100) -} - -func SubtestAll(t *testing.T, tr smux.Transport) { - - tests := []TransportTest{ - SubtestConstructSwarm, - SubtestSimpleWrite, - SubtestSimpleWrite100msgs, - SubtestStress1Swarm1Conn1Stream1Msg, - SubtestStress1Swarm1Conn1Stream100Msg, - SubtestStress1Swarm1Conn100Stream100Msg, - SubtestStress1Swarm10Conn50Stream50Msg, - SubtestStress5Swarm2Conn20Stream20Msg, - // SubtestStress10Swarm2Conn100Stream100Msg, <-- this hoses the osx network stack... - } - - for _, f := range tests { - if testing.Verbose() { - fmt.Fprintf(os.Stderr, "==== RUN %s\n", GetFunctionName(f)) - } - f(t, tr) - } -} - -type TransportTest func(t *testing.T, tr smux.Transport) - -func TestNoOp(t *testing.T) {} - -func GetFunctionName(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/stream.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/stream.go deleted file mode 100644 index c9033fce3..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/stream.go +++ /dev/null @@ -1,93 +0,0 @@ -package peerstream - -import ( - "fmt" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -// StreamHandler is a function which receives a Stream. It -// allows clients to set a function to receive newly created -// streams, and decide whether to continue adding them. -// It works sort of like a http.HandleFunc. -// Note: the StreamHandler is called sequentially, so spawn -// goroutines or pass the Stream. See EchoHandler. -type StreamHandler func(s *Stream) - -// Stream is an io.{Read,Write,Close}r to a remote counterpart. -// It wraps a spdystream.Stream, and links it to a Conn and groups -type Stream struct { - smuxStream smux.Stream - - conn *Conn - groups groupSet -} - -func newStream(ss smux.Stream, c *Conn) *Stream { - s := &Stream{ - conn: c, - smuxStream: ss, - groups: groupSet{m: make(map[Group]struct{})}, - } - s.groups.AddSet(&c.groups) // inherit groups - return s -} - -// String returns a string representation of the Stream -func (s *Stream) String() string { - f := " %s>" - return fmt.Sprintf(f, s.conn.NetConn().LocalAddr(), s.conn.NetConn().RemoteAddr()) -} - -// SPDYStream returns the underlying *spdystream.Stream -func (s *Stream) Stream() smux.Stream { - return s.smuxStream -} - -// Conn returns the Conn associated with this Stream -func (s *Stream) Conn() *Conn { - return s.conn -} - -// Swarm returns the Swarm asociated with this Stream -func (s *Stream) Swarm() *Swarm { - return s.conn.swarm -} - -// Groups returns the Groups this Stream belongs to -func (s *Stream) Groups() []Group { - return s.groups.Groups() -} - -// InGroup returns whether this stream belongs to a Group -func (s *Stream) InGroup(g Group) bool { - return s.groups.Has(g) -} - -// AddGroup assigns given Group to Stream -func (s *Stream) AddGroup(g Group) { - s.groups.Add(g) -} - -func (s *Stream) Read(p []byte) (n int, err error) { - return s.smuxStream.Read(p) -} - -func (s *Stream) Write(p []byte) (n int, err error) { - return s.smuxStream.Write(p) -} - -func (s *Stream) Close() error { - return s.conn.swarm.removeStream(s) -} - -// StreamsWithGroup narrows down a set of streams to those in given group. -func StreamsWithGroup(g Group, streams []*Stream) []*Stream { - var out []*Stream - for _, s := range streams { - if s.InGroup(g) { - out = append(out, s) - } - } - return out -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/swarm.go b/Godeps/_workspace/src/github.com/jbenet/go-peerstream/swarm.go deleted file mode 100644 index c15247182..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-peerstream/swarm.go +++ /dev/null @@ -1,404 +0,0 @@ -package peerstream - -import ( - "errors" - "fmt" - "net" - "sync" - "time" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -// fd is a (file) descriptor, unix style -type fd uint32 - -// GarbageCollectTimeout governs the periodic connection closer. -var GarbageCollectTimeout = 5 * time.Second - -type Swarm struct { - // the transport we'll use. - transport smux.Transport - - // active streams. - streams map[*Stream]struct{} - streamLock sync.RWMutex - - // active connections. generate new Streams - conns map[*Conn]struct{} - connLock sync.RWMutex - - // active listeners. generate new Listeners - listeners map[*Listener]struct{} - listenerLock sync.RWMutex - - // these handlers should be accessed with their getter/setter - // as this pointer may be changed at any time. - handlerLock sync.RWMutex // protects the functions below - connHandler ConnHandler // receives Conns intiated remotely - streamHandler StreamHandler // receives Streams initiated remotely - selectConn SelectConn // default SelectConn function - - // notification listeners - notifiees map[Notifiee]struct{} - notifieeLock sync.RWMutex - - closed chan struct{} -} - -func NewSwarm(t smux.Transport) *Swarm { - s := &Swarm{ - transport: t, - streams: make(map[*Stream]struct{}), - conns: make(map[*Conn]struct{}), - listeners: make(map[*Listener]struct{}), - notifiees: make(map[Notifiee]struct{}), - selectConn: SelectRandomConn, - streamHandler: NoOpStreamHandler, - connHandler: NoOpConnHandler, - closed: make(chan struct{}), - } - go s.connGarbageCollect() - return s -} - -// String returns a string with various internal stats -func (s *Swarm) String() string { - s.listenerLock.Lock() - ls := len(s.listeners) - s.listenerLock.Unlock() - - s.connLock.Lock() - cs := len(s.conns) - s.connLock.Unlock() - - s.streamLock.Lock() - ss := len(s.streams) - s.streamLock.Unlock() - - str := "" - return fmt.Sprintf(str, ls, cs, ss) -} - -// Dump returns a string with all the internal state -func (s *Swarm) Dump() string { - str := s.String() + "\n" - - s.listenerLock.Lock() - for l, _ := range s.listeners { - str += fmt.Sprintf("\t%s %v\n", l, l.Groups()) - } - s.listenerLock.Unlock() - - s.connLock.Lock() - for c, _ := range s.conns { - str += fmt.Sprintf("\t%s %v\n", c, c.Groups()) - } - s.connLock.Unlock() - - s.streamLock.Lock() - for ss, _ := range s.streams { - str += fmt.Sprintf("\t%s %v\n", ss, ss.Groups()) - } - s.streamLock.Unlock() - - return str -} - -// SetStreamHandler assigns the stream handler in the swarm. -// The handler assumes responsibility for closing the stream. -// This need not happen at the end of the handler, leaving the -// stream open (to be used and closed later) is fine. -// It is also fine to keep a pointer to the Stream. -// This is a threadsafe (atomic) operation -func (s *Swarm) SetStreamHandler(sh StreamHandler) { - s.handlerLock.Lock() - defer s.handlerLock.Unlock() - s.streamHandler = sh -} - -// StreamHandler returns the Swarm's current StreamHandler. -// This is a threadsafe (atomic) operation -func (s *Swarm) StreamHandler() StreamHandler { - s.handlerLock.RLock() - defer s.handlerLock.RUnlock() - if s.streamHandler == nil { - return NoOpStreamHandler - } - return s.streamHandler -} - -// SetConnHandler assigns the conn handler in the swarm. -// Unlike the StreamHandler, the ConnHandler has less respon- -// ibility for the Connection. The Swarm is still its client. -// This handler is only a notification. -// This is a threadsafe (atomic) operation -func (s *Swarm) SetConnHandler(ch ConnHandler) { - s.handlerLock.Lock() - defer s.handlerLock.Unlock() - s.connHandler = ch -} - -// ConnHandler returns the Swarm's current ConnHandler. -// This is a threadsafe (atomic) operation -func (s *Swarm) ConnHandler() ConnHandler { - s.handlerLock.RLock() - defer s.handlerLock.RUnlock() - if s.connHandler == nil { - return NoOpConnHandler - } - return s.connHandler -} - -// SetConnSelect assigns the connection selector in the swarm. -// If cs is nil, will use SelectRandomConn -// This is a threadsafe (atomic) operation -func (s *Swarm) SetSelectConn(cs SelectConn) { - s.handlerLock.Lock() - defer s.handlerLock.Unlock() - s.selectConn = cs -} - -// ConnSelect returns the Swarm's current connection selector. -// ConnSelect is used in order to select the best of a set of -// possible connections. The default chooses one at random. -// This is a threadsafe (atomic) operation -func (s *Swarm) SelectConn() SelectConn { - s.handlerLock.RLock() - defer s.handlerLock.RUnlock() - if s.selectConn == nil { - return SelectRandomConn - } - return s.selectConn -} - -// Conns returns all the connections associated with this Swarm. -func (s *Swarm) Conns() []*Conn { - s.connLock.RLock() - conns := make([]*Conn, 0, len(s.conns)) - for c := range s.conns { - conns = append(conns, c) - } - s.connLock.RUnlock() - - open := make([]*Conn, 0, len(conns)) - for _, c := range conns { - if c.smuxConn.IsClosed() { - c.GoClose() - } else { - open = append(open, c) - } - } - return open -} - -// Listeners returns all the listeners associated with this Swarm. -func (s *Swarm) Listeners() []*Listener { - s.listenerLock.RLock() - out := make([]*Listener, 0, len(s.listeners)) - for c := range s.listeners { - out = append(out, c) - } - s.listenerLock.RUnlock() - return out -} - -// Streams returns all the streams associated with this Swarm. -func (s *Swarm) Streams() []*Stream { - s.streamLock.RLock() - out := make([]*Stream, 0, len(s.streams)) - for c := range s.streams { - out = append(out, c) - } - s.streamLock.RUnlock() - return out -} - -// AddListener adds net.Listener to the Swarm, and immediately begins -// accepting incoming connections. -func (s *Swarm) AddListener(l net.Listener) (*Listener, error) { - return s.addListener(l) -} - -// AddListenerWithRateLimit adds Listener to the Swarm, and immediately -// begins accepting incoming connections. The rate of connection acceptance -// depends on the RateLimit option -// func (s *Swarm) AddListenerWithRateLimit(net.Listner, RateLimit) // TODO - -// AddConn gives the Swarm ownership of net.Conn. The Swarm will open a -// SPDY session and begin listening for Streams. -// Returns the resulting Swarm-associated peerstream.Conn. -// Idempotent: if the Connection has already been added, this is a no-op. -func (s *Swarm) AddConn(netConn net.Conn) (*Conn, error) { - return s.addConn(netConn, false) -} - -// NewStream opens a new Stream on the best available connection, -// as selected by current swarm.SelectConn. -func (s *Swarm) NewStream() (*Stream, error) { - return s.NewStreamSelectConn(s.SelectConn()) -} - -func (s *Swarm) newStreamSelectConn(selConn SelectConn, conns []*Conn) (*Stream, error) { - if selConn == nil { - return nil, errors.New("nil SelectConn") - } - - best := selConn(conns) - if best == nil || !ConnInConns(best, conns) { - return nil, ErrInvalidConnSelected - } - return s.NewStreamWithConn(best) -} - -// NewStreamWithSelectConn opens a new Stream on a connection selected -// by selConn. -func (s *Swarm) NewStreamSelectConn(selConn SelectConn) (*Stream, error) { - if selConn == nil { - return nil, errors.New("nil SelectConn") - } - - conns := s.Conns() - if len(conns) == 0 { - return nil, ErrNoConnections - } - return s.newStreamSelectConn(selConn, conns) -} - -// NewStreamWithGroup opens a new Stream on an available connection in -// the given group. Uses the current swarm.SelectConn to pick between -// multiple connections. -func (s *Swarm) NewStreamWithGroup(group Group) (*Stream, error) { - conns := s.ConnsWithGroup(group) - return s.newStreamSelectConn(s.SelectConn(), conns) -} - -// NewStreamWithNetConn opens a new Stream on given net.Conn. -// Calls s.AddConn(netConn). -func (s *Swarm) NewStreamWithNetConn(netConn net.Conn) (*Stream, error) { - c, err := s.AddConn(netConn) - if err != nil { - return nil, err - } - return s.NewStreamWithConn(c) -} - -// NewStreamWithConnection opens a new Stream on given connection. -func (s *Swarm) NewStreamWithConn(conn *Conn) (*Stream, error) { - if conn == nil { - return nil, errors.New("nil Conn") - } - if conn.Swarm() != s { - return nil, errors.New("connection not associated with swarm") - } - - if conn.smuxConn.IsClosed() { - go conn.Close() - return nil, errors.New("conn is closed") - } - - s.connLock.RLock() - if _, found := s.conns[conn]; !found { - s.connLock.RUnlock() - return nil, errors.New("connection not associated with swarm") - } - s.connLock.RUnlock() - return s.createStream(conn) -} - -// AddConnToGroup assigns given Group to conn -func (s *Swarm) AddConnToGroup(conn *Conn, g Group) { - conn.groups.Add(g) -} - -// ConnsWithGroup returns all the connections with a given Group -func (s *Swarm) ConnsWithGroup(g Group) []*Conn { - return ConnsWithGroup(g, s.Conns()) -} - -// StreamsWithGroup returns all the streams with a given Group -func (s *Swarm) StreamsWithGroup(g Group) []*Stream { - return StreamsWithGroup(g, s.Streams()) -} - -// Close shuts down the Swarm, and it's listeners. -func (s *Swarm) Close() error { - defer close(s.closed) - - // automatically close everything new we get. - s.SetConnHandler(func(c *Conn) { c.Close() }) - s.SetStreamHandler(func(s *Stream) { s.Close() }) - - var wgl sync.WaitGroup - for _, l := range s.Listeners() { - wgl.Add(1) - go func(list *Listener) { - list.Close() - wgl.Done() - }(l) - } - wgl.Wait() - - var wgc sync.WaitGroup - for _, c := range s.Conns() { - wgc.Add(1) - go func(conn *Conn) { - conn.Close() - wgc.Done() - }(c) - } - wgc.Wait() - return nil -} - -// connGarbageCollect periodically sweeps conns to make sure -// they're still alive. if any are closed, remvoes them. -func (s *Swarm) connGarbageCollect() { - for { - select { - case <-s.closed: - return - case <-time.After(GarbageCollectTimeout): - } - - for _, c := range s.Conns() { - if c.smuxConn.IsClosed() { - go c.Close() - } - } - } -} - -// Notify signs up Notifiee to receive signals when events happen -func (s *Swarm) Notify(n Notifiee) { - s.notifieeLock.Lock() - s.notifiees[n] = struct{}{} - s.notifieeLock.Unlock() -} - -// StopNotify unregisters Notifiee fromr receiving signals -func (s *Swarm) StopNotify(n Notifiee) { - s.notifieeLock.Lock() - delete(s.notifiees, n) - s.notifieeLock.Unlock() -} - -// notifyAll runs the notification function on all Notifiees -func (s *Swarm) notifyAll(notification func(n Notifiee)) { - s.notifieeLock.RLock() - for n := range s.notifiees { - // make sure we dont block - // and they dont block each other. - go notification(n) - } - s.notifieeLock.RUnlock() -} - -// Notifiee is an interface for an object wishing to receive -// notifications from a Swarm -type Notifiee interface { - Connected(*Conn) // called when a connection opened - Disconnected(*Conn) // called when a connection closed - OpenedStream(*Stream) // called when a stream opened - ClosedStream(*Stream) // called when a stream closed -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/.travis.yml b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/.travis.yml deleted file mode 100644 index d16d679a6..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go - -go: - - 1.3 - - 1.4 - - release - - tip - -script: - - go test -race -cpu=5 -v ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/LICENSE b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/LICENSE deleted file mode 100644 index 0d760cbb4..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2013 Conformal Systems LLC. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/README.md b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/README.md deleted file mode 100644 index f373e5935..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# go-reuseport - -[![travisbadge](https://travis-ci.org/jbenet/go-reuseport.svg)](https://travis-ci.org/jbenet/go-reuseport) - -This package enables listening and dialing from _the same_ TCP or UDP port. -This means that the following sockopts are set: - -``` -SO_REUSEADDR -SO_REUSEPORT -``` - -- godoc: https://godoc.org/github.com/jbenet/go-reuseport - -This is a simple package to get around the problem of reusing addresses. -The go `net` package (to my knowledge) does not allow setting socket options. -This is particularly problematic when attempting to do TCP NAT holepunching, -which requires a process to both Listen and Dial on the same TCP port. -This package makes this possible for me. It is a pretty narrow use case, but -perhaps this package can grow to be more general over time. - -## Examples - - -```Go -// listen on the same port. oh yeah. -l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") -l2, _ := reuse.Listen("tcp", "127.0.0.1:1234") -``` - -```Go -// dial from the same port. oh yeah. -l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") -l2, _ := reuse.Listen("tcp", "127.0.0.1:1235") -c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235") -``` - -**Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, and doing so would clash.** - -## Tested - -Tested on `darwin` and `linux`. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/addr.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/addr.go deleted file mode 100644 index cfffc7c8c..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/addr.go +++ /dev/null @@ -1,20 +0,0 @@ -package reuseport - -import ( - "net" -) - -func ResolveAddr(network, address string) (net.Addr, error) { - switch network { - default: - return nil, net.UnknownNetworkError(network) - case "ip", "ip4", "ip6": - return net.ResolveIPAddr(network, address) - case "tcp", "tcp4", "tcp6": - return net.ResolveTCPAddr(network, address) - case "udp", "udp4", "udp6": - return net.ResolveUDPAddr(network, address) - case "unix", "unixgram", "unixpacket": - return net.ResolveUnixAddr(network, address) - } -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/available_unix.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/available_unix.go deleted file mode 100644 index fb52a87cd..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/available_unix.go +++ /dev/null @@ -1,91 +0,0 @@ -// +build darwin freebsd dragonfly netbsd openbsd linux - -package reuseport - -import ( - "sync" - "sync/atomic" - "syscall" - "time" -) - -// checker is a struct to gather the availability check fields + funcs. -// we use atomic ints because this is potentially a really hot function call. -type checkerT struct { - avail int32 // atomic int managed by set/isAvailable() - check int32 // atomic int managed by has/checked() - mu sync.Mutex // synchonizes the actual check -} - -// the static location of the vars. -var checker checkerT - -func (c *checkerT) isAvailable() bool { - return atomic.LoadInt32(&c.avail) != 0 -} - -func (c *checkerT) setIsAvailable(b bool) { - if b { - atomic.StoreInt32(&c.avail, 1) - } else { - atomic.StoreInt32(&c.avail, 0) - } -} - -func (c *checkerT) hasChecked() bool { - return atomic.LoadInt32(&c.check) != 0 -} - -func (c *checkerT) setHasChecked(b bool) { - if b { - atomic.StoreInt32(&c.check, 1) - } else { - atomic.StoreInt32(&c.check, 0) - } -} - -// Available returns whether or not SO_REUSEPORT is available in the OS. -// It does so by attepting to open a tcp listener, setting the option, and -// checking ENOPROTOOPT on error. After checking, the decision is cached -// for the rest of the process run. -func available() bool { - if checker.hasChecked() { - return checker.isAvailable() - } - - // synchronize, only one should check - checker.mu.Lock() - defer checker.mu.Unlock() - - // we blocked. someone may have been gotten this. - if checker.hasChecked() { - return checker.isAvailable() - } - - // there may be fluke reasons to fail to add a listener. - // so we give it 5 shots. if not, give up and call it not avail. - for i := 0; i < 5; i++ { - // try to listen at tcp port 0. - l, err := listenStream("tcp", "127.0.0.1:0") - if err == nil { - // no error? available. - checker.setIsAvailable(true) - checker.setHasChecked(true) - l.Close() // Go back to the Shadow! - return true - } - - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.ENOPROTOOPT { - break // :( that's all folks. - } - } - - // not an errno? or not ENOPROTOOPT? retry. - <-time.After(20 * time.Millisecond) // wait a bit - } - - checker.setIsAvailable(false) - checker.setHasChecked(true) - return false -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_bsd.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_bsd.go deleted file mode 100644 index 480ddbbb8..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_bsd.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build darwin freebsd dragonfly netbsd openbsd - -package reuseport - -import ( - "syscall" -) - -var soReusePort = syscall.SO_REUSEPORT -var soReuseAddr = syscall.SO_REUSEADDR diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_linux.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_linux.go deleted file mode 100644 index 93ddfd90e..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/const_linux.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build linux - -package reuseport - -import ( - "syscall" -) - -var soReusePort = 15 // this is not defined in unix go pkg. -var soReuseAddr = syscall.SO_REUSEADDR diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go deleted file mode 100644 index c58303f34..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go +++ /dev/null @@ -1,362 +0,0 @@ -// +build darwin freebsd dragonfly netbsd openbsd linux - -package reuseport - -import ( - "net" - "os" - "strconv" - "syscall" - "time" - - poll "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll" - sockaddrnet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net" -) - -const ( - filePrefix = "port." -) - -// Wrapper around the socket system call that marks the returned file -// descriptor as nonblocking and close-on-exec. -func socket(family, socktype, protocol int) (fd int, err error) { - syscall.ForkLock.RLock() - fd, err = syscall.Socket(family, socktype, protocol) - if err == nil { - syscall.CloseOnExec(fd) - } - syscall.ForkLock.RUnlock() - - if err != nil { - return -1, err - } - - // cant set it until after connect - // if err = syscall.SetNonblock(fd, true); err != nil { - // syscall.Close(fd) - // return -1, err - // } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReuseAddr, 1); err != nil { - syscall.Close(fd) - return -1, err - } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil { - syscall.Close(fd) - return -1, err - } - - // set setLinger to 5 as reusing exact same (srcip:srcport, dstip:dstport) - // will otherwise fail on connect. - if err = setLinger(fd, 5); err != nil { - syscall.Close(fd) - return -1, err - } - - return fd, nil -} - -func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { - var ( - fd int - lfamily int - rfamily int - socktype int - lprotocol int - rprotocol int - file *os.File - deadline time.Time - remoteSockaddr syscall.Sockaddr - localSockaddr syscall.Sockaddr - ) - - netAddr, err := ResolveAddr(netw, addr) - if err != nil { - return nil, err - } - - switch netAddr.(type) { - case *net.TCPAddr, *net.UDPAddr: - default: - return nil, ErrUnsupportedProtocol - } - - switch { - case !dialer.Deadline.IsZero(): - deadline = dialer.Deadline - case dialer.Timeout != 0: - deadline = time.Now().Add(dialer.Timeout) - } - - localSockaddr = sockaddrnet.NetAddrToSockaddr(dialer.LocalAddr) - remoteSockaddr = sockaddrnet.NetAddrToSockaddr(netAddr) - - rfamily = sockaddrnet.NetAddrAF(netAddr) - rprotocol = sockaddrnet.NetAddrIPPROTO(netAddr) - socktype = sockaddrnet.NetAddrSOCK(netAddr) - - if dialer.LocalAddr != nil { - switch dialer.LocalAddr.(type) { - case *net.TCPAddr, *net.UDPAddr: - default: - return nil, ErrUnsupportedProtocol - } - - // check family and protocols match. - lfamily = sockaddrnet.NetAddrAF(dialer.LocalAddr) - lprotocol = sockaddrnet.NetAddrIPPROTO(dialer.LocalAddr) - if lfamily != rfamily && lprotocol != rfamily { - return nil, &net.AddrError{Err: "unexpected address type", Addr: netAddr.String()} - } - } - - // look at dialTCP in http://golang.org/src/net/tcpsock_posix.go .... ! - // here we just try again 3 times. - for i := 0; i < 3; i++ { - if !deadline.IsZero() && deadline.Before(time.Now()) { - if err == nil { - err = errTimeout - } - break - } - - if fd, err = socket(rfamily, socktype, rprotocol); err != nil { - return nil, err - } - - if localSockaddr != nil { - if err = syscall.Bind(fd, localSockaddr); err != nil { - syscall.Close(fd) - return nil, err - } - } - - if err = syscall.SetNonblock(fd, true); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = connect(fd, remoteSockaddr, deadline); err != nil { - syscall.Close(fd) - continue // try again. - } - - break - } - if err != nil { - return nil, err - } - - if rprotocol == syscall.IPPROTO_TCP { - // by default golang/net sets TCP no delay to true. - if err = setNoDelay(fd, true); err != nil { - syscall.Close(fd) - return nil, err - } - } - - // File Name get be nil - file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) - if c, err = net.FileConn(file); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = file.Close(); err != nil { - syscall.Close(fd) - c.Close() - return nil, err - } - - // c = wrapConnWithRemoteAddr(c, netAddr) - return c, err -} - -func listen(netw, addr string) (fd int, err error) { - var ( - family int - socktype int - protocol int - sockaddr syscall.Sockaddr - ) - - netAddr, err := ResolveAddr(netw, addr) - if err != nil { - return -1, err - } - - switch netAddr.(type) { - case *net.TCPAddr, *net.UDPAddr: - default: - return -1, ErrUnsupportedProtocol - } - - family = sockaddrnet.NetAddrAF(netAddr) - protocol = sockaddrnet.NetAddrIPPROTO(netAddr) - sockaddr = sockaddrnet.NetAddrToSockaddr(netAddr) - socktype = sockaddrnet.NetAddrSOCK(netAddr) - - if fd, err = socket(family, socktype, protocol); err != nil { - return -1, err - } - - if err = syscall.Bind(fd, sockaddr); err != nil { - syscall.Close(fd) - return -1, err - } - - if protocol == syscall.IPPROTO_TCP { - // by default golang/net sets TCP no delay to true. - if err = setNoDelay(fd, true); err != nil { - syscall.Close(fd) - return -1, err - } - } - - if err = syscall.SetNonblock(fd, true); err != nil { - syscall.Close(fd) - return -1, err - } - - return fd, nil -} - -func listenStream(netw, addr string) (l net.Listener, err error) { - var ( - file *os.File - ) - - fd, err := listen(netw, addr) - if err != nil { - return nil, err - } - - // Set backlog size to the maximum - if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil { - syscall.Close(fd) - return nil, err - } - - file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) - if l, err = net.FileListener(file); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = file.Close(); err != nil { - syscall.Close(fd) - l.Close() - return nil, err - } - - return l, err -} - -func listenPacket(netw, addr string) (p net.PacketConn, err error) { - var ( - file *os.File - ) - - fd, err := listen(netw, addr) - if err != nil { - return nil, err - } - - file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) - if p, err = net.FilePacketConn(file); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = file.Close(); err != nil { - syscall.Close(fd) - p.Close() - return nil, err - } - - return p, err -} - -func listenUDP(netw, addr string) (c net.Conn, err error) { - var ( - file *os.File - ) - - fd, err := listen(netw, addr) - if err != nil { - return nil, err - } - - file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) - if c, err = net.FileConn(file); err != nil { - syscall.Close(fd) - return nil, err - } - - if err = file.Close(); err != nil { - syscall.Close(fd) - return nil, err - } - - return c, err -} - -// this is close to the connect() function inside stdlib/net -func connect(fd int, ra syscall.Sockaddr, deadline time.Time) error { - switch err := syscall.Connect(fd, ra); err { - case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: - case nil, syscall.EISCONN: - if !deadline.IsZero() && deadline.Before(time.Now()) { - return errTimeout - } - return nil - default: - return err - } - - poller, err := poll.New(fd) - if err != nil { - return err - } - defer poller.Close() - - for { - if err = poller.WaitWrite(deadline); err != nil { - return err - } - - // if err := fd.pd.WaitWrite(); err != nil { - // return err - // } - // i'd use the above fd.pd.WaitWrite to poll io correctly, just like net sockets... - // but of course, it uses the damn runtime_* functions that _cannot_ be used by - // non-go-stdlib source... seriously guys, this is not nice. - // we're relegated to using syscall.Select (what nightmare that is) or using - // a simple but totally bogus time-based wait. such garbage. - var nerr int - nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR) - if err != nil { - return err - } - switch err = syscall.Errno(nerr); err { - case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: - continue - case syscall.Errno(0), syscall.EISCONN: - if !deadline.IsZero() && deadline.Before(time.Now()) { - return errTimeout - } - return nil - default: - return err - } - } -} - -var errTimeout = &timeoutError{} - -type timeoutError struct{} - -func (e *timeoutError) Error() string { return "i/o timeout (reuseport)" } -func (e *timeoutError) Timeout() bool { return true } -func (e *timeoutError) Temporary() bool { return true } diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_windows.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_windows.go deleted file mode 100644 index c33b2eed7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_windows.go +++ /dev/null @@ -1,28 +0,0 @@ -package reuseport - -import "net" - -// TODO. for now, just pass it over to net.Listen/net.Dial - -func listen(network, address string) (net.Listener, error) { - return net.Listen(network, address) -} - -func listenPacket(netw, laddr string) (net.PacketConn, error) { - return net.ListenPacket(netw, laddr) -} - -func listenStream(netw, addr string) (net.Listener, error) { - return listen(netw, addr) -} - -func dial(dialer net.Dialer, network, address string) (net.Conn, error) { - return dialer.Dial(network, address) -} - -// on windows, we just use the regular functions. sources -// vary on this-- some claim port reuse behavior is on by default -// on some windows systems. So we try. may the force be with you. -func available() bool { - return true -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go deleted file mode 100644 index d20b3b4c6..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go +++ /dev/null @@ -1,110 +0,0 @@ -// Package reuseport provides Listen and Dial functions that set socket options -// in order to be able to reuse ports. You should only use this package if you -// know what SO_REUSEADDR and SO_REUSEPORT are. -// -// For example: -// -// // listen on the same port. oh yeah. -// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") -// l2, _ := reuse.Listen("tcp", "127.0.0.1:1234") -// -// // dial from the same port. oh yeah. -// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") -// l2, _ := reuse.Listen("tcp", "127.0.0.1:1235") -// c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235") -// -// Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, -// and doing so would clash. -package reuseport - -import ( - "errors" - "net" - "syscall" - "time" -) - -// Available returns whether or not SO_REUSEPORT is available in the OS. -// It does so by attepting to open a tcp listener, setting the option, and -// checking ENOPROTOOPT on error. After checking, the decision is cached -// for the rest of the process run. -func Available() bool { - return available() -} - -// ErrUnsuportedProtocol signals that the protocol is not currently -// supported by this package. This package currently only supports TCP. -var ErrUnsupportedProtocol = errors.New("protocol not yet supported") - -// ErrReuseFailed is returned if a reuse attempt was unsuccessful. -var ErrReuseFailed = errors.New("reuse failed") - -// Listen listens at the given network and address. see net.Listen -// Returns a net.Listener created from a file discriptor for a socket -// with SO_REUSEPORT and SO_REUSEADDR option set. -func Listen(network, address string) (net.Listener, error) { - if !available() { - return nil, syscall.Errno(syscall.ENOPROTOOPT) - } - - return listenStream(network, address) -} - -// ListenPacket listens at the given network and address. see net.ListenPacket -// Returns a net.Listener created from a file discriptor for a socket -// with SO_REUSEPORT and SO_REUSEADDR option set. -func ListenPacket(network, address string) (net.PacketConn, error) { - if !available() { - return nil, syscall.Errno(syscall.ENOPROTOOPT) - } - - return listenPacket(network, address) -} - -// Dial dials the given network and address. see net.Dialer.Dial -// Returns a net.Conn created from a file discriptor for a socket -// with SO_REUSEPORT and SO_REUSEADDR option set. -func Dial(network, laddr, raddr string) (net.Conn, error) { - if !available() { - return nil, syscall.Errno(syscall.ENOPROTOOPT) - } - - var d Dialer - if laddr != "" { - netladdr, err := ResolveAddr(network, laddr) - if err != nil { - return nil, err - } - d.D.LocalAddr = netladdr - } - - return d.Dial(network, raddr) -} - -// Dialer is used to specify the Dial options, much like net.Dialer. -// We simply wrap a net.Dialer. -type Dialer struct { - D net.Dialer -} - -// Dial dials the given network and address. see net.Dialer.Dial -// Returns a net.Conn created from a file discriptor for a socket -// with SO_REUSEPORT and SO_REUSEADDR option set. -func (d *Dialer) Dial(network, address string) (net.Conn, error) { - if !available() { - return nil, syscall.Errno(syscall.ENOPROTOOPT) - } - - return dial(d.D, network, address) -} - -func (d *Dialer) deadline(def time.Duration) time.Time { - switch { - case !d.D.Deadline.IsZero(): - return d.D.Deadline - case d.D.Timeout != 0: - return time.Now().Add(d.D.Timeout) - default: - return time.Now().Add(def) - } -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/opts_posix.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/opts_posix.go deleted file mode 100644 index cc5774ff3..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/opts_posix.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -package reuseport - -import ( - "os" - "syscall" -) - -func boolint(b bool) int { - if b { - return 1 - } - return 0 -} - -func setNoDelay(fd int, noDelay bool) error { - return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))) -} - -func setLinger(fd int, sec int) error { - var l syscall.Linger - if sec >= 0 { - l.Onoff = 1 - l.Linger = int32(sec) - } else { - l.Onoff = 0 - l.Linger = 0 - } - return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/error.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/error.go deleted file mode 100644 index 28b26a9d2..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/error.go +++ /dev/null @@ -1,9 +0,0 @@ -package poll - -var errTimeout = &timeoutError{} - -type timeoutError struct{} - -func (e *timeoutError) Error() string { return "i/o timeout (reuseport poll)" } -func (e *timeoutError) Timeout() bool { return true } -func (e *timeoutError) Temporary() bool { return true } diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_bsd.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_bsd.go deleted file mode 100644 index 918f416f4..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_bsd.go +++ /dev/null @@ -1,59 +0,0 @@ -// +build darwin,amd64 darwin,arm64 freebsd dragonfly netbsd openbsd - -package poll - -import ( - "syscall" - "time" -) - -type Poller struct { - kqfd int - event syscall.Kevent_t -} - -func New(fd int) (p *Poller, err error) { - p = &Poller{} - - p.kqfd, err = syscall.Kqueue() - if p.kqfd == -1 || err != nil { - return nil, err - } - - p.event = syscall.Kevent_t{ - Ident: uint64(fd), - Filter: syscall.EVFILT_WRITE, - Flags: syscall.EV_ADD | syscall.EV_ENABLE | syscall.EV_ONESHOT, - Fflags: 0, - Data: 0, - Udata: nil, - } - return p, nil -} - -func (p *Poller) Close() error { - return syscall.Close(p.kqfd) -} - -func (p *Poller) WaitWrite(deadline time.Time) error { - - // setup timeout - var timeout *syscall.Timespec - if !deadline.IsZero() { - d := deadline.Sub(time.Now()) - t := syscall.NsecToTimespec(d.Nanoseconds()) - timeout = &t - } - - // wait on kevent - events := make([]syscall.Kevent_t, 1) - n, err := syscall.Kevent(p.kqfd, []syscall.Kevent_t{p.event}, events, timeout) - if err != nil { - return err - } - - if n < 1 { - return errTimeout - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_darwin_386.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_darwin_386.go deleted file mode 100644 index 6cff81dfd..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_darwin_386.go +++ /dev/null @@ -1,57 +0,0 @@ -package poll - -import ( - "syscall" - "time" -) - -type Poller struct { - kqfd int - event syscall.Kevent_t -} - -func New(fd int) (p *Poller, err error) { - p = &Poller{} - - p.kqfd, err = syscall.Kqueue() - if p.kqfd == -1 || err != nil { - return nil, err - } - - p.event = syscall.Kevent_t{ - Ident: uint32(fd), - Filter: syscall.EVFILT_WRITE, - Flags: syscall.EV_ADD | syscall.EV_ENABLE | syscall.EV_ONESHOT, - Fflags: 0, - Data: 0, - Udata: nil, - } - return p, nil -} - -func (p *Poller) Close() error { - return syscall.Close(p.kqfd) -} - -func (p *Poller) WaitWrite(deadline time.Time) error { - - // setup timeout - var timeout *syscall.Timespec - if !deadline.IsZero() { - d := deadline.Sub(time.Now()) - t := syscall.NsecToTimespec(d.Nanoseconds()) - timeout = &t - } - - // wait on kevent - events := make([]syscall.Kevent_t, 1) - n, err := syscall.Kevent(p.kqfd, []syscall.Kevent_t{p.event}, events, timeout) - if err != nil { - return err - } - - if n < 1 { - return errTimeout - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_linux.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_linux.go deleted file mode 100644 index b63a00091..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_linux.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build linux - -package poll - -import ( - "syscall" - "time" -) - -type Poller struct { - epfd int - event syscall.EpollEvent - events [32]syscall.EpollEvent -} - -func New(fd int) (p *Poller, err error) { - p = &Poller{} - if p.epfd, err = syscall.EpollCreate1(0); err != nil { - return nil, err - } - - p.event.Events = syscall.EPOLLOUT - p.event.Fd = int32(fd) - if err = syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &p.event); err != nil { - p.Close() - return nil, err - } - - return p, nil -} - -func (p *Poller) Close() error { - return syscall.Close(p.epfd) -} - -func (p *Poller) WaitWrite(deadline time.Time) error { - msec := -1 - if !deadline.IsZero() { - d := deadline.Sub(time.Now()) - msec = int(d.Nanoseconds() / 1000000) // ms!? omg... - } - - n, err := syscall.EpollWait(p.epfd, p.events[:], msec) - if err != nil { - return err - } - if n < 1 { - return errTimeout - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_unsupported.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_unsupported.go deleted file mode 100644 index bc0e5ed83..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/poll/poll_unsupported.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build windows plan9 - -package poll - -import ( - "errors" -) - -func WaitWrite(fd int) error { - return errors.New("platform not supported") -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/reuse_test.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/reuse_test.go deleted file mode 100644 index cd613432d..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/reuse_test.go +++ /dev/null @@ -1,579 +0,0 @@ -package reuseport - -import ( - "bytes" - "errors" - "fmt" - "io" - "net" - "os" - "os/exec" - "strings" - "sync" - "testing" - "time" -) - -func echo(c net.Conn) { - io.Copy(c, c) - c.Close() -} - -func packetEcho(c net.PacketConn) { - defer c.Close() - buf := make([]byte, 65536) - for { - n, addr, err := c.ReadFrom(buf) - if err != nil { - return - } - if _, err := c.WriteTo(buf[:n], addr); err != nil { - return - } - } -} - -func acceptAndEcho(l net.Listener) { - for { - c, err := l.Accept() - if err != nil { - return - } - go echo(c) - } -} - -func CI() bool { - return os.Getenv("TRAVIS") == "true" -} - -func TestStreamListenSamePort(t *testing.T) { - - // any ports - any := [][]string{ - []string{"tcp", "0.0.0.0:0"}, - []string{"tcp4", "0.0.0.0:0"}, - []string{"tcp6", "[::]:0"}, - - []string{"tcp", "127.0.0.1:0"}, - []string{"tcp", "[::1]:0"}, - []string{"tcp4", "127.0.0.1:0"}, - []string{"tcp6", "[::1]:0"}, - } - - // specific ports. off in CI - specific := [][]string{ - []string{"tcp", "127.0.0.1:5556"}, - []string{"tcp", "[::1]:5557"}, - []string{"tcp4", "127.0.0.1:5558"}, - []string{"tcp6", "[::1]:5559"}, - } - - testCases := any - if !CI() { - testCases = append(testCases, specific...) - } - - for _, tcase := range testCases { - network := tcase[0] - addr := tcase[1] - t.Log("testing", network, addr) - - l1, err := Listen(network, addr) - if err != nil { - t.Fatal(err) - continue - } - defer l1.Close() - t.Log("listening", l1.Addr()) - - l2, err := Listen(l1.Addr().Network(), l1.Addr().String()) - if err != nil { - t.Fatal(err) - continue - } - defer l2.Close() - t.Log("listening", l2.Addr()) - - l3, err := Listen(l2.Addr().Network(), l2.Addr().String()) - if err != nil { - t.Fatal(err) - continue - } - defer l3.Close() - t.Log("listening", l3.Addr()) - - if l1.Addr().String() != l2.Addr().String() { - t.Fatal("addrs should match", l1.Addr(), l2.Addr()) - } - - if l1.Addr().String() != l3.Addr().String() { - t.Fatal("addrs should match", l1.Addr(), l3.Addr()) - } - } -} - -func TestPacketListenSamePort(t *testing.T) { - - // any ports - any := [][]string{ - []string{"udp", "0.0.0.0:0"}, - []string{"udp4", "0.0.0.0:0"}, - []string{"udp6", "[::]:0"}, - - []string{"udp", "127.0.0.1:0"}, - []string{"udp", "[::1]:0"}, - []string{"udp4", "127.0.0.1:0"}, - []string{"udp6", "[::1]:0"}, - } - - // specific ports. off in CI - specific := [][]string{ - []string{"udp", "127.0.0.1:5560"}, - []string{"udp", "[::1]:5561"}, - []string{"udp4", "127.0.0.1:5562"}, - []string{"udp6", "[::1]:5563"}, - } - - testCases := any - if !CI() { - testCases = append(testCases, specific...) - } - - for _, tcase := range testCases { - network := tcase[0] - addr := tcase[1] - t.Log("testing", network, addr) - - l1, err := ListenPacket(network, addr) - if err != nil { - t.Fatal(err) - continue - } - defer l1.Close() - t.Log("listening", l1.LocalAddr()) - - l2, err := ListenPacket(l1.LocalAddr().Network(), l1.LocalAddr().String()) - if err != nil { - t.Fatal(err) - continue - } - defer l2.Close() - t.Log("listening", l2.LocalAddr()) - - l3, err := ListenPacket(l2.LocalAddr().Network(), l2.LocalAddr().String()) - if err != nil { - t.Fatal(err) - continue - } - defer l3.Close() - t.Log("listening", l3.LocalAddr()) - - if l1.LocalAddr().String() != l2.LocalAddr().String() { - t.Fatal("addrs should match", l1.LocalAddr(), l2.LocalAddr()) - } - - if l1.LocalAddr().String() != l3.LocalAddr().String() { - t.Fatal("addrs should match", l1.LocalAddr(), l3.LocalAddr()) - } - } -} - -func TestStreamListenDialSamePort(t *testing.T) { - - any := [][]string{ - []string{"tcp", "0.0.0.0:0", "0.0.0.0:0"}, - []string{"tcp4", "0.0.0.0:0", "0.0.0.0:0"}, - []string{"tcp6", "[::]:0", "[::]:0"}, - - []string{"tcp", "127.0.0.1:0", "127.0.0.1:0"}, - []string{"tcp4", "127.0.0.1:0", "127.0.0.1:0"}, - []string{"tcp6", "[::1]:0", "[::1]:0"}, - } - - specific := [][]string{ - []string{"tcp", "127.0.0.1:0", "127.0.0.1:5571"}, - []string{"tcp4", "127.0.0.1:0", "127.0.0.1:5573"}, - []string{"tcp6", "[::1]:0", "[::1]:5574"}, - []string{"tcp", "127.0.0.1:5570", "127.0.0.1:0"}, - []string{"tcp4", "127.0.0.1:5572", "127.0.0.1:0"}, - []string{"tcp6", "[::1]:5573", "[::1]:0"}, - } - - testCases := any - if !CI() { - testCases = append(testCases, specific...) - } - - for _, tcase := range testCases { - t.Log("testing", tcase) - network := tcase[0] - addr1 := tcase[1] - addr2 := tcase[2] - - l1, err := Listen(network, addr1) - if err != nil { - t.Fatal(err) - continue - } - defer l1.Close() - t.Log("listening", l1.Addr()) - - l2, err := Listen(network, addr2) - if err != nil { - t.Fatal(err) - continue - } - defer l2.Close() - t.Log("listening", l2.Addr()) - - go acceptAndEcho(l1) - go acceptAndEcho(l2) - - c1, err := Dial(network, l1.Addr().String(), l2.Addr().String()) - if err != nil { - t.Fatal(err, network, l1.Addr().String(), l2.Addr().String()) - continue - } - defer c1.Close() - t.Log("dialed", c1, c1.LocalAddr(), c1.RemoteAddr()) - - if getPort(l1.Addr()) != getPort(c1.LocalAddr()) { - t.Fatal("addrs should match", l1.Addr(), c1.LocalAddr()) - } - - if getPort(l2.Addr()) != getPort(c1.RemoteAddr()) { - t.Fatal("addrs should match", l2.Addr(), c1.RemoteAddr()) - } - - hello1 := []byte("hello world") - hello2 := make([]byte, len(hello1)) - if _, err := c1.Write(hello1); err != nil { - t.Fatal(err) - continue - } - - if _, err := c1.Read(hello2); err != nil { - t.Fatal(err) - continue - } - - if !bytes.Equal(hello1, hello2) { - t.Fatal("echo failed", string(hello1), "!=", string(hello2)) - } - t.Log("echoed", string(hello2)) - c1.Close() - } -} - -func TestStreamListenDialSamePortStressManyMsgs(t *testing.T) { - testCases := [][]string{ - []string{"tcp", "127.0.0.1:0"}, - []string{"tcp4", "127.0.0.1:0"}, - []string{"tcp6", "[::]:0"}, - } - - for _, tcase := range testCases { - subestStreamListenDialSamePortStress(t, tcase[0], tcase[1], 2, 1000) - } -} - -func TestStreamListenDialSamePortStressManyNodes(t *testing.T) { - testCases := [][]string{ - []string{"tcp", "127.0.0.1:0"}, - []string{"tcp4", "127.0.0.1:0"}, - []string{"tcp6", "[::]:0"}, - } - - for _, tcase := range testCases { - subestStreamListenDialSamePortStress(t, tcase[0], tcase[1], 50, 1) - } -} - -func TestStreamListenDialSamePortStressManyMsgsManyNodes(t *testing.T) { - testCases := [][]string{ - []string{"tcp", "127.0.0.1:0"}, - []string{"tcp4", "127.0.0.1:0"}, - []string{"tcp6", "[::]:0"}, - } - - for _, tcase := range testCases { - subestStreamListenDialSamePortStress(t, tcase[0], tcase[1], 50, 100) - } -} - -func subestStreamListenDialSamePortStress(t *testing.T, network, addr string, nodes int, msgs int) { - t.Logf("testing %s:%s %d nodes %d msgs", network, addr, nodes, msgs) - - var ls []net.Listener - for i := 0; i < nodes; i++ { - l, err := Listen(network, addr) - if err != nil { - t.Fatal(err) - } - defer l.Close() - go acceptAndEcho(l) - ls = append(ls, l) - t.Logf("listening %s", l.Addr()) - } - - // connect them all - var cs []net.Conn - for i := 0; i < nodes; i++ { - for j := 0; j < i; j++ { - if i == j { - continue // cannot do self. - } - - ia := ls[i].Addr().String() - ja := ls[j].Addr().String() - c, err := Dial(network, ia, ja) - if err != nil { - t.Fatal(network, ia, ja, err) - } - defer c.Close() - cs = append(cs, c) - t.Logf("dialed %s --> %s", c.LocalAddr(), c.RemoteAddr()) - } - } - - errs := make(chan error) - - send := func(c net.Conn, buf []byte) { - if _, err := c.Write(buf); err != nil { - errs <- err - } - } - - recv := func(c net.Conn, buf []byte) { - buf2 := make([]byte, len(buf)) - if _, err := c.Read(buf2); err != nil { - errs <- err - } - if !bytes.Equal(buf, buf2) { - errs <- fmt.Errorf("recv failure: %s <--> %s -- %s %s", c.RemoteAddr(), c.LocalAddr(), buf, buf2) - } - } - - t.Logf("sending %d msgs per conn", msgs) - go func() { - var wg sync.WaitGroup - for _, c := range cs { - wg.Add(1) - go func(c net.Conn) { - defer wg.Done() - for i := 0; i < msgs; i++ { - msg := []byte(fmt.Sprintf("message %d", i)) - send(c, msg) - recv(c, msg) - } - }(c) - } - wg.Wait() - close(errs) - }() - - for err := range errs { - if err != nil { - t.Error(err) - } - } -} - -func TestPacketListenDialSamePort(t *testing.T) { - - any := [][]string{ - []string{"udp", "0.0.0.0:0", "0.0.0.0:0"}, - []string{"udp4", "0.0.0.0:0", "0.0.0.0:0"}, - []string{"udp6", "[::]:0", "[::]:0"}, - - []string{"udp", "127.0.0.1:0", "127.0.0.1:0"}, - []string{"udp4", "127.0.0.1:0", "127.0.0.1:0"}, - []string{"udp6", "[::1]:0", "[::1]:0"}, - } - - specific := [][]string{ - []string{"udp", "127.0.0.1:5670", "127.0.0.1:5671"}, - []string{"udp4", "127.0.0.1:5672", "127.0.0.1:5673"}, - []string{"udp6", "[::1]:5673", "[::1]:5674"}, - } - - testCases := any - if !CI() { - testCases = append(testCases, specific...) - } - - for _, tcase := range testCases { - t.Log("testing", tcase) - network := tcase[0] - addr1 := tcase[1] - addr2 := tcase[2] - - l1, err := ListenPacket(network, addr1) - if err != nil { - t.Fatal(err) - continue - } - defer l1.Close() - t.Log("listening", l1.LocalAddr()) - - l2, err := ListenPacket(network, addr2) - if err != nil { - t.Fatal(err) - continue - } - defer l2.Close() - t.Log("listening", l2.LocalAddr()) - - go packetEcho(l1) - go packetEcho(l2) - - c1, err := Dial(network, l1.LocalAddr().String(), l2.LocalAddr().String()) - if err != nil { - t.Fatal(err) - continue - } - defer c1.Close() - t.Log("dialed", c1.LocalAddr(), c1.RemoteAddr()) - - if getPort(l1.LocalAddr()) != getPort(c1.LocalAddr()) { - t.Fatal("addrs should match", l1.LocalAddr(), c1.LocalAddr()) - } - - if getPort(l2.LocalAddr()) != getPort(c1.RemoteAddr()) { - t.Fatal("addrs should match", l2.LocalAddr(), c1.RemoteAddr()) - } - - hello1 := []byte("hello world") - hello2 := make([]byte, len(hello1)) - if _, err := c1.Write(hello1); err != nil { - t.Fatal(err) - continue - } - - if _, err := c1.Read(hello2); err != nil { - t.Fatal(err) - continue - } - - if !bytes.Equal(hello1, hello2) { - t.Fatal("echo failed", string(hello1), "!=", string(hello2)) - } - t.Log("echoed", string(hello2)) - } -} - -func TestDialRespectsTimeout(t *testing.T) { - - testCases := [][]string{ - []string{"tcp", "127.0.0.1:6780", "1.2.3.4:6781"}, - []string{"tcp4", "127.0.0.1:6782", "1.2.3.4:6783"}, - []string{"tcp6", "[::1]:6784", "[::2]:6785"}, - } - - timeout := 50 * time.Millisecond - - for _, tcase := range testCases { - network := tcase[0] - laddr := tcase[1] - raddr := tcase[2] - - // l, err := Listen(network, raddr) - // if err != nil { - // t.Error("without a listener it wont work") - // continue - // } - // defer l.Close() - - nladdr, err := ResolveAddr(network, laddr) - if err != nil { - t.Error("failed to resolve addr", network, laddr, err) - continue - } - t.Log("testing", network, nladdr, raddr) - - d := Dialer{ - D: net.Dialer{ - LocalAddr: nil, - Timeout: timeout, - }, - } - - errs := make(chan error) - go func() { - c, err := d.Dial(network, raddr) - if err == nil { - c.Close() - errs <- errors.New("should've not connected") - return - } - close(errs) // success! - }() - - ErrDrain: - select { - case <-time.After(5 * time.Second): - t.Fatal("took too long") - case err, more := <-errs: - if !more { - break - } - t.Error(err) - goto ErrDrain - } - - } -} - -func TestUnixNotSupported(t *testing.T) { - - testCases := [][]string{ - []string{"unix", "/tmp/foo"}, - } - - for _, tcase := range testCases { - network := tcase[0] - addr := tcase[1] - t.Log("testing", network, addr) - - l, err := Listen(network, addr) - if err == nil { - l.Close() - t.Fatal("unix supported") - continue - } - } -} - -func TestOpenFDs(t *testing.T) { - // this is a totally ad-hoc limit. test harnesses may add fds. - // but if this is really much higher than 20, there's obviously leaks. - limit := 20 - start := time.Now() - for countOpenFiles(t) > limit { - <-time.After(time.Second) - t.Log("open fds:", countOpenFiles(t)) - if time.Now().Sub(start) > (time.Second * 15) { - t.Error("fd leak!") - } - } -} - -func countOpenFiles(t *testing.T) int { - out, err := exec.Command("/bin/sh", "-c", fmt.Sprintf("lsof -p %v", os.Getpid())).Output() - if err != nil { - t.Fatal(err) - } - return bytes.Count(out, []byte("\n")) -} - -func getPort(a net.Addr) string { - if a == nil { - return "" - } - s := strings.Split(a.String(), ":") - if len(s) > 1 { - return s[1] - } - return "" -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/.gitignore b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/.gitignore deleted file mode 100644 index 9daeafb98..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go deleted file mode 100644 index d5ec13726..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net" - "os" - - reuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport" - resolve "gx/ipfs/Qma73Sqt13DzHzveZ667BBfraM7MuMrPepUXjmv812JhRS/go-net-resolve-addr" -) - -func main() { - - l1, err := reuse.Listen("tcp", "0.0.0.0:11111") - maybeDie(err) - fmt.Printf("listening on %s\n", l1.Addr()) - - l2, err := reuse.Listen("tcp", "0.0.0.0:22222") - maybeDie(err) - fmt.Printf("listening on %s\n", l2.Addr()) - - a1, err := resolve.ResolveAddr("dial", "tcp", "127.0.0.1:11111") - maybeDie(err) - - a3, err := resolve.ResolveAddr("dial", "tcp", "127.0.0.1:33333") - maybeDie(err) - - d1 := reuse.Dialer{net.Dialer{LocalAddr: a1}} - d2 := reuse.Dialer{net.Dialer{LocalAddr: a3}} - - go func() { - l2to1foo, err := l2.Accept() - maybeDie(err) - fmt.Printf("%s accepted conn from %s\n", addrStr(l2.Addr()), addrStr(l2to1foo.RemoteAddr())) - - fmt.Println("safe") - - l1to2bar, err := l1.Accept() - maybeDie(err) - fmt.Printf("%s accepted conn from %s\n", addrStr(l1.Addr()), addrStr(l1to2bar.RemoteAddr())) - - io.Copy(l1to2bar, l2to1foo) - }() - - d1to2foo, err := d1.Dial("tcp4", "127.0.0.1:22222") - maybeDie(err) - fmt.Printf("dialing from %s to %s\n", d1.D.LocalAddr, "127.0.0.1:22222") - - d2to1bar, err := d2.Dial("tcp4", "127.0.0.1:11111") - maybeDie(err) - fmt.Printf("dialing from %s to %s\n", d2.D.LocalAddr, "127.0.0.1:11111") - - go io.Copy(d1to2foo, os.Stdin) - io.Copy(os.Stdout, d2to1bar) -} - -func die(err error) { - fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(-1) -} - -func maybeDie(err error) { - if err != nil { - die(err) - } -} - -func addrStr(a net.Addr) string { - return fmt.Sprintf("%s/%s", a.Network(), a) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net.go b/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net.go deleted file mode 100644 index 9299d08ff..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net.go +++ /dev/null @@ -1,341 +0,0 @@ -// package sockaddrnet provides conversions between net.Addr and syscall.Sockaddr -package sockaddrnet - -import ( - "net" - "syscall" -) - -// NetAddrAF returns the syscall AF_* type for a given net.Addr -// returns AF_UNSPEC if unknown -func NetAddrAF(addr net.Addr) int { - switch addr := addr.(type) { - case *net.IPAddr: - return IPAF(addr.IP) - - case *net.TCPAddr: - return IPAF(addr.IP) - - case *net.UDPAddr: - return IPAF(addr.IP) - - case *net.UnixAddr: - return AF_UNIX - - default: - return AF_UNSPEC - } -} - -// IPAF returns the syscall AF_* type for a given IP address -// returns AF_UNSPEC if unknown -func IPAF(ip net.IP) int { - switch { - case ip.To4() != nil: - return AF_INET - - case ip.To16() != nil: - return AF_INET6 - - default: - return AF_UNSPEC - } -} - -// NetAddrIPPROTO returns the syscall IPPROTO_* type for a given net.Addr -// returns -1 if protocol unknown -func NetAddrIPPROTO(addr net.Addr) int { - switch addr := addr.(type) { - case *net.IPAddr: - switch { - default: - return IPPROTO_IP - - case addr.IP.To4() != nil: - return IPPROTO_IPV4 - - case addr.IP.To16() != nil: - return IPPROTO_IPV6 - } - - case *net.TCPAddr: - return IPPROTO_TCP - - case *net.UDPAddr: - return IPPROTO_UDP - - default: - return -1 - } -} - -// NetAddrSOCK returns the syscall SOCK_* type for a given net.Addr -// returns 0 if type unknown -func NetAddrSOCK(addr net.Addr) int { - switch addr := addr.(type) { - case *net.IPAddr: - return SOCK_DGRAM - case *net.TCPAddr: - return SOCK_STREAM - case *net.UDPAddr: - return SOCK_DGRAM - case *net.UnixAddr: - switch addr.Net { - default: - return 0 - case "unix": - return SOCK_STREAM - case "unixgram": - return SOCK_DGRAM - case "unixpacket": - return SOCK_SEQPACKET - } - default: - return 0 - } -} - -// NetAddrToSockaddr converts a net.Addr to a syscall.Sockaddr. -// Returns nil if the input is invalid or conversion is not possible. -func NetAddrToSockaddr(addr net.Addr) syscall.Sockaddr { - switch addr := addr.(type) { - case *net.IPAddr: - return IPAddrToSockaddr(addr) - case *net.TCPAddr: - return TCPAddrToSockaddr(addr) - case *net.UDPAddr: - return UDPAddrToSockaddr(addr) - case *net.UnixAddr: - sa, _ := UnixAddrToSockaddr(addr) - return sa - default: - return nil - } -} - -// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr -// Returns nil if conversion fails. -func IPAndZoneToSockaddr(ip net.IP, zone string) syscall.Sockaddr { - switch { - case len(ip) < net.IPv4len: // default to IPv4 - buf := [4]byte{0, 0, 0, 0} - return &syscall.SockaddrInet4{Addr: buf} - - case ip.To4() != nil: - var buf [4]byte - copy(buf[:], ip[12:16]) // last 4 bytes - return &syscall.SockaddrInet4{Addr: buf} - - case ip.To16() != nil: - var buf [16]byte - copy(buf[:], ip) - return &syscall.SockaddrInet6{Addr: buf, ZoneId: uint32(IP6ZoneToInt(zone))} - } - panic("should be unreachable") -} - -// IPAddrToSockaddr converts a net.IPAddr to a syscall.Sockaddr. -// Returns nil if conversion fails. -func IPAddrToSockaddr(addr *net.IPAddr) syscall.Sockaddr { - return IPAndZoneToSockaddr(addr.IP, addr.Zone) -} - -// TCPAddrToSockaddr converts a net.TCPAddr to a syscall.Sockaddr. -// Returns nil if conversion fails. -func TCPAddrToSockaddr(addr *net.TCPAddr) syscall.Sockaddr { - sa := IPAndZoneToSockaddr(addr.IP, addr.Zone) - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - sa.Port = addr.Port - return sa - case *syscall.SockaddrInet6: - sa.Port = addr.Port - return sa - default: - return nil - } -} - -// UDPAddrToSockaddr converts a net.UDPAddr to a syscall.Sockaddr. -// Returns nil if conversion fails. -func UDPAddrToSockaddr(addr *net.UDPAddr) syscall.Sockaddr { - sa := IPAndZoneToSockaddr(addr.IP, addr.Zone) - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - sa.Port = addr.Port - return sa - case *syscall.SockaddrInet6: - sa.Port = addr.Port - return sa - default: - return nil - } -} - -// UnixAddrToSockaddr converts a net.UnixAddr to a syscall.Sockaddr, and returns -// the type (syscall.SOCK_STREAM, syscall.SOCK_DGRAM, syscall.SOCK_SEQPACKET) -// Returns (nil, 0) if conversion fails. -func UnixAddrToSockaddr(addr *net.UnixAddr) (syscall.Sockaddr, int) { - t := 0 - switch addr.Net { - case "unix": - t = syscall.SOCK_STREAM - case "unixgram": - t = syscall.SOCK_DGRAM - case "unixpacket": - t = syscall.SOCK_SEQPACKET - default: - return nil, 0 - } - return &syscall.SockaddrUnix{Name: addr.Name}, t -} - -// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr -// Returns nil if conversion fails. -func SockaddrToIPAndZone(sa syscall.Sockaddr) (net.IP, string) { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ip := make([]byte, 16) - copy(ip[12:16], sa.Addr[:]) - return ip, "" - - case *syscall.SockaddrInet6: - ip := make([]byte, 16) - copy(ip, sa.Addr[:]) - return ip, IP6ZoneToString(int(sa.ZoneId)) - } - return nil, "" -} - -// SockaddrToIPAddr converts a syscall.Sockaddr to a net.IPAddr -// Returns nil if conversion fails. -func SockaddrToIPAddr(sa syscall.Sockaddr) *net.IPAddr { - ip, zone := SockaddrToIPAndZone(sa) - switch sa.(type) { - case *syscall.SockaddrInet4: - return &net.IPAddr{IP: ip} - case *syscall.SockaddrInet6: - return &net.IPAddr{IP: ip, Zone: zone} - } - return nil -} - -// SockaddrToTCPAddr converts a syscall.Sockaddr to a net.TCPAddr -// Returns nil if conversion fails. -func SockaddrToTCPAddr(sa syscall.Sockaddr) *net.TCPAddr { - ip, zone := SockaddrToIPAndZone(sa) - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - return &net.TCPAddr{IP: ip, Port: sa.Port} - case *syscall.SockaddrInet6: - return &net.TCPAddr{IP: ip, Port: sa.Port, Zone: zone} - } - return nil -} - -// SockaddrToUDPAddr converts a syscall.Sockaddr to a net.UDPAddr -// Returns nil if conversion fails. -func SockaddrToUDPAddr(sa syscall.Sockaddr) *net.UDPAddr { - ip, zone := SockaddrToIPAndZone(sa) - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - return &net.UDPAddr{IP: ip, Port: sa.Port} - case *syscall.SockaddrInet6: - return &net.UDPAddr{IP: ip, Port: sa.Port, Zone: zone} - } - return nil -} - -// from: go/src/pkg/net/unixsock_posix.go - -// SockaddrToUnixAddr converts a syscall.Sockaddr to a net.UnixAddr -// Returns nil if conversion fails. -func SockaddrToUnixAddr(sa syscall.Sockaddr) *net.UnixAddr { - if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &net.UnixAddr{Name: s.Name, Net: "unix"} - } - return nil -} - -// SockaddrToUnixgramAddr converts a syscall.Sockaddr to a net.UnixAddr -// Returns nil if conversion fails. -func SockaddrToUnixgramAddr(sa syscall.Sockaddr) *net.UnixAddr { - if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &net.UnixAddr{Name: s.Name, Net: "unixgram"} - } - return nil -} - -// SockaddrToUnixpacketAddr converts a syscall.Sockaddr to a net.UnixAddr -// Returns nil if conversion fails. -func SockaddrToUnixpacketAddr(sa syscall.Sockaddr) *net.UnixAddr { - if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &net.UnixAddr{Name: s.Name, Net: "unixpacket"} - } - return nil -} - -// from: go/src/pkg/net/ipsock.go - -// IP6ZoneToString converts an IP6 Zone syscall int to a net string -// returns "" if zone is 0 -func IP6ZoneToString(zone int) string { - if zone == 0 { - return "" - } - if ifi, err := net.InterfaceByIndex(zone); err == nil { - return ifi.Name - } - return itod(uint(zone)) -} - -// IP6ZoneToInt converts an IP6 Zone net string to a syscall int -// returns 0 if zone is "" -func IP6ZoneToInt(zone string) int { - if zone == "" { - return 0 - } - if ifi, err := net.InterfaceByName(zone); err == nil { - return ifi.Index - } - n, _, _ := dtoi(zone, 0) - return n -} - -// from: go/src/pkg/net/parse.go - -// Convert i to decimal string. -func itod(i uint) string { - if i == 0 { - return "0" - } - - // Assemble decimal in reverse order. - var b [32]byte - bp := len(b) - for ; i > 0; i /= 10 { - bp-- - b[bp] = byte(i%10) + '0' - } - - return string(b[bp:]) -} - -// Bigger than we need, not too big to worry about overflow -const big = 0xFFFFFF - -// Decimal to integer starting at &s[i0]. -// Returns number, new offset, success. -func dtoi(s string, i0 int) (n int, i int, ok bool) { - n = 0 - for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { - n = n*10 + int(s[i]-'0') - if n >= big { - return 0, i, false - } - } - if i == i0 { - return 0, i, false - } - return n, i, true -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_bsd.go b/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_bsd.go deleted file mode 100644 index a38c2bd48..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_bsd.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd - -package sockaddrnet - -import ( - "syscall" -) - -const ( - AF_INET = syscall.AF_INET - AF_INET6 = syscall.AF_INET6 - AF_UNIX = syscall.AF_UNIX - AF_UNSPEC = syscall.AF_UNSPEC - - IPPROTO_IP = syscall.IPPROTO_IP - IPPROTO_IPV4 = syscall.IPPROTO_IPV4 - IPPROTO_IPV6 = syscall.IPPROTO_IPV6 - IPPROTO_TCP = syscall.IPPROTO_TCP - IPPROTO_UDP = syscall.IPPROTO_UDP - - SOCK_DGRAM = syscall.SOCK_DGRAM - SOCK_STREAM = syscall.SOCK_STREAM - SOCK_SEQPACKET = syscall.SOCK_SEQPACKET -) diff --git a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_linux.go b/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_linux.go deleted file mode 100644 index ddc4ec45a..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_linux.go +++ /dev/null @@ -1,22 +0,0 @@ -package sockaddrnet - -import ( - "syscall" -) - -const ( - AF_INET = syscall.AF_INET - AF_INET6 = syscall.AF_INET6 - AF_UNIX = syscall.AF_UNIX - AF_UNSPEC = syscall.AF_UNSPEC - - IPPROTO_IP = syscall.IPPROTO_IP - IPPROTO_IPV4 = syscall.IPPROTO_IPIP - IPPROTO_IPV6 = syscall.IPPROTO_IPV6 - IPPROTO_TCP = syscall.IPPROTO_TCP - IPPROTO_UDP = syscall.IPPROTO_UDP - - SOCK_DGRAM = syscall.SOCK_DGRAM - SOCK_STREAM = syscall.SOCK_STREAM - SOCK_SEQPACKET = syscall.SOCK_SEQPACKET -) diff --git a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_windows.go b/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_windows.go deleted file mode 100644 index 6f54bfffc..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-sockaddr/net/net_windows.go +++ /dev/null @@ -1,22 +0,0 @@ -package sockaddrnet - -import ( - "syscall" -) - -const ( - AF_INET = syscall.AF_INET - AF_INET6 = syscall.AF_INET6 - AF_UNIX = syscall.AF_UNIX - AF_UNSPEC = syscall.AF_UNSPEC - - IPPROTO_IP = syscall.IPPROTO_IP - IPPROTO_IPV4 = syscall.IPPROTO_IPV4 - IPPROTO_IPV6 = syscall.IPPROTO_IPV6 - IPPROTO_TCP = syscall.IPPROTO_TCP - IPPROTO_UDP = syscall.IPPROTO_UDP - - SOCK_DGRAM = syscall.SOCK_DGRAM - SOCK_STREAM = syscall.SOCK_STREAM - SOCK_SEQPACKET = syscall.SOCK_SEQPACKET -) diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/.travis.yml b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/.travis.yml deleted file mode 100644 index 415030aa9..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.3 - - 1.4 - - release - - tip - -script: - - go test ./... - # - go test -race -cpu=5 ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Godeps.json b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Godeps.json deleted file mode 100644 index 346185df7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Godeps.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "ImportPath": "github.com/jbenet/go-stream-muxer", - "GoVersion": "go1.4.2", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/docker/spdystream", - "Rev": "b2c3287865f3ad6aa22821ddb7b4692b896ac207" - }, - { - "ImportPath": "github.com/hashicorp/yamux", - "Rev": "b2e55852ddaf823a85c67f798080eb7d08acd71d" - }, - { - "ImportPath": "github.com/inconshreveable/muxado", - "Rev": "f693c7e88ba316d1a0ae3e205e22a01aa3ec2848" - }, - { - "ImportPath": "github.com/whyrusleeping/go-multiplex", - "Rev": "474b9aebeb391746f304ddf7c764a5da12319857" - }, - { - "ImportPath": "github.com/whyrusleeping/go-multistream", - "Rev": "31bb014803a6eba2261bda5593e42c016a5f33bb" - } - ] -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Readme b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Readme deleted file mode 100644 index 4cdaa53d5..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/LICENSE b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/LICENSE deleted file mode 100644 index c7386b3c9..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Juan Batiz-Benet - -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. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Makefile b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Makefile deleted file mode 100644 index f15fcaa68..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -godep: - go get github.com/tools/godep - -vendor: godep - godep save -r ./... - -build: - go build ./... - -test: - go test ./... - -test_race: - go test -race -cpu 5 ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/README.md b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/README.md deleted file mode 100644 index a0a08869a..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# go-stream-muxer - generalized stream multiplexing - - -go-stream-muxer is a common interface for stream muxers, with common tests. It wraps other stream muxers (like [muxado](https://github.com/inconshreveable/muxado), [spdystream](https://github.com/docker/spdystream) and [yamux](https://github.com/hashicorp/yamux)). - -[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) - -> A test suite and interface you can use to implement a stream muxer. - -### Godoc: https://godoc.org/github.com/jbenet/go-stream-muxer - -## Implementations - -* [yamux](yamux) -* [muxado](muxado) -* [multiplex](multiplex) -* [spdystream](spdystream) - -## Badge - -Include this badge in your readme if you make a new module that uses abstract-stream-muxer API. - -![](img/badge.png) - -## Client example - -```go -import ( - "net" - "fmt" - "io" - ymux "github.com/jbenet/go-stream-muxer/yamux" - smux "github.com/jbenet/go-stream-muxer" -) - -func dial() { - nconn, _ := net.Dial("tcp", "localhost:1234") - sconn, _ := ymux.DefaultTransport.NewConn(nconn, false) // false == client - - go sconn.Serve(func(smux.Stream) {}) // no-op - - s1, _ := sconn.OpenStream() - s1.Write([]byte("hello")) - - s2, _ := sconn.OpenStream() - s2.Write([]byte("world")) - - length := 20 - buf2 := make([]byte, length) - fmt.Printf("reading %d bytes from stream (echoed)\n", length) - - s1.Read(buf2) - - fmt.Printf("received %s as a response\n", string(buf2)) - - s3, _ := sconn.OpenStream() - io.Copy(s3, os.Stdin) -} -``` - -## Server example - -```go -import ( - "net" - "fmt" - "io" - ymux "github.com/jbenet/go-stream-muxer/yamux" - smux "github.com/jbenet/go-stream-muxer" -) - -func listen() { - tr := ymux.DefaultTransport - l, _ := net.Listen("tcp", "localhost:1234") - - go func() { - for { - c, _ := l.Accept() - - fmt.Println("accepted connection") - sc, _ := tr.NewConn(c, true) - - go sc.Serve(func(s smux.Stream) { - fmt.Println("serving connection") - echoStream(s) - }) - } - }() -} - -func echoStream(s smux.Stream) { - defer s.Close() - - fmt.Println("accepted stream") - io.Copy(s, s) // echo everything - fmt.Println("closing stream") -} -``` diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/img/badge.png b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/img/badge.png deleted file mode 100644 index 738bcf4a2..000000000 Binary files a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/img/badge.png and /dev/null differ diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex.go deleted file mode 100644 index 69b093b67..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex.go +++ /dev/null @@ -1,56 +0,0 @@ -package peerstream_multiplex - -import ( - "errors" - "net" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" - mp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex" // Conn is a connection to a remote peer. -) - -var ErrUseServe = errors.New("not implemented, use Serve") - -type conn struct { - *mp.Multiplex -} - -func (c *conn) Close() error { - return c.Multiplex.Close() -} - -func (c *conn) IsClosed() bool { - return c.Multiplex.IsClosed() -} - -// OpenStream creates a new stream. -func (c *conn) OpenStream() (smux.Stream, error) { - return c.Multiplex.NewStream(), nil -} - -// AcceptStream accepts a stream opened by the other side. -func (c *conn) AcceptStream() (smux.Stream, error) { - return c.Multiplex.Accept() -} - -// Serve starts listening for incoming requests and handles them -// using given StreamHandler -func (c *conn) Serve(handler smux.StreamHandler) { - for { - s, err := c.AcceptStream() - if err != nil { - return - } - go handler(s) - } -} - -// Transport is a go-peerstream transport that constructs -// multiplex-backed connections. -type Transport struct{} - -// DefaultTransport has default settings for multiplex -var DefaultTransport = &Transport{} - -func (t *Transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) { - return &conn{mp.NewMultiplex(nc, isServer)}, nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex_test.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex_test.go deleted file mode 100644 index de4b691d7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex/multiplex_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package peerstream_multiplex - -import ( - "testing" - - test "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test" -) - -func TestMultiplexTransport(t *testing.T) { - test.SubtestAll(t, DefaultTransport) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream.go deleted file mode 100644 index d60396ab1..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream.go +++ /dev/null @@ -1,60 +0,0 @@ -// package multistream implements a peerstream transport using -// go-multistream to select the underlying stream muxer -package multistream - -import ( - "net" - - mss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" - multiplex "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multiplex" - spdy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream" - yamux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux" -) - -type transport struct { - mux *mss.MultistreamMuxer - - tpts map[string]smux.Transport -} - -func NewTransport() smux.Transport { - mux := mss.NewMultistreamMuxer() - mux.AddHandler("/multiplex", nil) - mux.AddHandler("/spdystream", nil) - mux.AddHandler("/yamux", nil) - - tpts := map[string]smux.Transport{ - "/multiplex": multiplex.DefaultTransport, - "/spdystream": spdy.Transport, - "/yamux": yamux.DefaultTransport, - } - - return &transport{ - mux: mux, - tpts: tpts, - } -} - -func (t *transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) { - var proto string - if isServer { - selected, _, err := t.mux.Negotiate(nc) - if err != nil { - return nil, err - } - proto = selected - } else { - // prefer yamux - selected, err := mss.SelectOneOf([]string{"/yamux", "/spdystream", "/multiplex"}, nc) - if err != nil { - return nil, err - } - proto = selected - } - - tpt := t.tpts[proto] - - return tpt.NewConn(nc, isServer) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream_test.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream_test.go deleted file mode 100644 index bfacf2ed4..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream/multistream_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package multistream - -import ( - "testing" - - test "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test" -) - -func TestMultiStreamTransport(t *testing.T) { - test.SubtestAll(t, NewTransport()) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go deleted file mode 100644 index e1b6a3313..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go +++ /dev/null @@ -1,105 +0,0 @@ -package peerstream_muxado - -import ( - "net" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" - muxado "gx/ipfs/QmaZ9WavcC9EKocNHof8onR8JHci2Qt8AuybkFaxJdr51Q/muxado" -) - -// stream implements smux.Stream using a ss.Stream -type stream struct { - ms muxado.Stream -} - -func (s *stream) muxadoStream() muxado.Stream { - return s.ms -} - -func (s *stream) Read(buf []byte) (int, error) { - return s.ms.Read(buf) -} - -func (s *stream) Write(buf []byte) (int, error) { - return s.ms.Write(buf) -} - -func (s *stream) Close() error { - return s.ms.Close() -} - -// Conn is a connection to a remote peer. -type conn struct { - ms muxado.Session - - closed chan struct{} -} - -func (c *conn) muxadoSession() muxado.Session { - return c.ms -} - -func (c *conn) Close() error { - return c.ms.Close() -} - -func (c *conn) IsClosed() bool { - select { - case <-c.closed: - return true - default: - return false - } -} - -// OpenStream creates a new stream. -func (c *conn) OpenStream() (smux.Stream, error) { - s, err := c.ms.Open() - if err != nil { - return nil, err - } - - return &stream{ms: s}, nil -} - -// AcceptStream accepts a stream opened by the other side. -func (c *conn) AcceptStream() (smux.Stream, error) { - s, err := c.ms.Accept() - if err != nil { - return nil, err - } - return &stream{ms: s}, nil -} - -// Serve starts listening for incoming requests and handles them -// using given StreamHandler -func (c *conn) Serve(handler smux.StreamHandler) { - for { // accept loop - s, err := c.AcceptStream() - if err != nil { - return // err always means closed. - } - go handler(s) - } -} - -type transport struct{} - -// Transport is a go-peerstream transport that constructs -// spdystream-backed connections. -var Transport = transport{} - -func (t transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) { - var s muxado.Session - if isServer { - s = muxado.Server(nc) - } else { - s = muxado.Client(nc) - } - cl := make(chan struct{}) - go func() { - s.Wait() - close(cl) - }() - return &conn{ms: s, closed: cl}, nil -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado_test.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado_test.go deleted file mode 100644 index 91726a9ed..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package peerstream_muxado - -import ( - "testing" - - test "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test" -) - -func TestMuxadoTransport(t *testing.T) { - test.SubtestAll(t, Transport) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxer.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxer.go deleted file mode 100644 index e9531750a..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxer.go +++ /dev/null @@ -1,46 +0,0 @@ -package streammux - -import ( - "io" - "net" -) - -// Stream is a bidirectional io pipe within a connection -type Stream interface { - io.Reader - io.Writer - io.Closer -} - -// StreamHandler is a function that handles streams -// (usually those opened by the remote side) -type StreamHandler func(Stream) - -// NoOpHandler do nothing. close streams as soon as they are opened. -var NoOpHandler = func(s Stream) { s.Close() } - -// Conn is a stream-multiplexing connection to a remote peer. -type Conn interface { - io.Closer - - // IsClosed returns whether a connection is fully closed, so it can - // be garbage collected. - IsClosed() bool - - // OpenStream creates a new stream. - OpenStream() (Stream, error) - - // AcceptStream accepts a stream opened by the other side. - AcceptStream() (Stream, error) - - // Serve starts a loop, accepting incoming requests and calling - // `StreamHandler with them. (Use _instead of_ accept. not both.) - Serve(StreamHandler) -} - -// Transport constructs go-stream-muxer compatible connections. -type Transport interface { - - // NewConn constructs a new connection - NewConn(c net.Conn, isServer bool) (Conn, error) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream.go deleted file mode 100644 index 25830832c..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream.go +++ /dev/null @@ -1,123 +0,0 @@ -package peerstream_spdystream - -import ( - "errors" - "net" - "net/http" - - ss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream" - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -var ErrUseServe = errors.New("not implemented, use Serve") - -// stream implements smux.Stream using a ss.Stream -type stream ss.Stream - -func (s *stream) spdyStream() *ss.Stream { - return (*ss.Stream)(s) -} - -func (s *stream) Read(buf []byte) (int, error) { - return s.spdyStream().Read(buf) -} - -func (s *stream) Write(buf []byte) (int, error) { - return s.spdyStream().Write(buf) -} - -func (s *stream) Close() error { - // Reset is spdystream's full bidirectional close. - // We expose bidirectional close as our `Close`. - // To close only half of the connection, and use other - // spdystream options, just get the stream with: - // ssStream := (*ss.Stream)(stream) - return s.spdyStream().Reset() -} - -// Conn is a connection to a remote peer. -type conn struct { - sc *ss.Connection - - closed chan struct{} -} - -func (c *conn) spdyConn() *ss.Connection { - return c.sc -} - -func (c *conn) Close() error { - err := c.spdyConn().CloseWait() - if !c.IsClosed() { - close(c.closed) - } - return err -} - -func (c *conn) IsClosed() bool { - select { - case <-c.closed: - return true - case <-c.sc.CloseChan(): - return true - default: - return false - } -} - -// OpenStream creates a new stream. -func (c *conn) OpenStream() (smux.Stream, error) { - s, err := c.spdyConn().CreateStream(http.Header{ - ":method": []string{"GET"}, // this is here for HTTP/SPDY interop - ":path": []string{"/"}, // this is here for HTTP/SPDY interop - }, nil, false) - if err != nil { - return nil, err - } - - // wait for a response before writing. for some reason - // spdystream does not make forward progress unless you do this. - s.Wait() - return (*stream)(s), nil -} - -// AcceptStream accepts a stream opened by the other side. -func (c *conn) AcceptStream() (smux.Stream, error) { - return nil, ErrUseServe -} - -// Serve starts listening for incoming requests and handles them -// using given StreamHandler -func (c *conn) Serve(handler smux.StreamHandler) { - c.spdyConn().Serve(func(s *ss.Stream) { - - // Flow control and backpressure of Opening streams is broken. - // I believe that spdystream has one set of workers that both send - // data AND accept new streams (as it's just more data). there - // is a problem where if the new stream handlers want to throttle, - // they also eliminate the ability to read/write data, which makes - // forward-progress impossible. Thus, throttling this function is - // -- at this moment -- not the solution. Either spdystream must - // change, or we must throttle another way. go-peerstream handles - // every new stream in its own goroutine. - err := s.SendReply(http.Header{}, false) - if err != nil { - // this _could_ error out. not sure how to handle this failure. - // don't return, and let the caller handle a broken stream. - // better than _hiding_ an error. - // return - } - go handler((*stream)(s)) - }) -} - -type transport struct{} - -// Transport is a go-peerstream transport that constructs -// spdystream-backed connections. -var Transport = transport{} - -func (t transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) { - sc, err := ss.NewConnection(nc, isServer) - return &conn{sc: sc, closed: make(chan struct{})}, err -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream_test.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream_test.go deleted file mode 100644 index 97f3d17e4..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/spdystream/spdystream_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package peerstream_spdystream - -import ( - "testing" - - test "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test" -) - -func TestSpdyStreamTransport(t *testing.T) { - test.SubtestAll(t, Transport) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test/ttest.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test/ttest.go deleted file mode 100644 index 371f6de00..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test/ttest.go +++ /dev/null @@ -1,378 +0,0 @@ -package sm_test - -import ( - "bytes" - crand "crypto/rand" - "fmt" - "io" - mrand "math/rand" - "net" - "os" - "reflect" - "runtime" - "runtime/debug" - "sync" - "testing" - - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -var randomness []byte - -func init() { - // read 1MB of randomness - randomness = make([]byte, 1<<20) - if _, err := crand.Read(randomness); err != nil { - panic(err) - } -} - -type Options struct { - tr smux.Transport - connNum int - streamNum int - msgNum int - msgMin int - msgMax int -} - -func randBuf(size int) []byte { - n := len(randomness) - size - if size < 1 { - panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness))) - } - - start := mrand.Intn(n) - return randomness[start : start+size] -} - -func checkErr(t *testing.T, err error) { - if err != nil { - debug.PrintStack() - t.Fatal(err) - } -} - -func log(s string, v ...interface{}) { - if testing.Verbose() { - fmt.Fprintf(os.Stderr, "> "+s+"\n", v...) - } -} - -func echoStream(s smux.Stream) { - defer s.Close() - log("accepted stream") - io.Copy(&LogWriter{s}, s) // echo everything - log("closing stream") -} - -type LogWriter struct { - W io.Writer -} - -func (lw *LogWriter) Write(buf []byte) (int, error) { - if testing.Verbose() { - log("logwriter: writing %d bytes", len(buf)) - } - return lw.W.Write(buf) -} - -func GoServe(t *testing.T, tr smux.Transport, l net.Listener) (done func()) { - closed := make(chan struct{}, 1) - - go func() { - for { - c1, err := l.Accept() - if err != nil { - select { - case <-closed: - return // closed naturally. - default: - checkErr(t, err) - } - } - - log("accepted connection") - sc1, err := tr.NewConn(c1, true) - checkErr(t, err) - go sc1.Serve(echoStream) - } - }() - - return func() { - closed <- struct{}{} - } -} - -func SubtestSimpleWrite(t *testing.T, tr smux.Transport) { - l, err := net.Listen("tcp", "localhost:0") - checkErr(t, err) - log("listening at %s", l.Addr().String()) - done := GoServe(t, tr, l) - defer done() - - log("dialing to %s", l.Addr().String()) - nc1, err := net.Dial("tcp", l.Addr().String()) - checkErr(t, err) - defer nc1.Close() - - log("wrapping conn") - c1, err := tr.NewConn(nc1, false) - checkErr(t, err) - defer c1.Close() - - // serve the outgoing conn, because some muxers assume - // that we _always_ call serve. (this is an error?) - go c1.Serve(smux.NoOpHandler) - - log("creating stream") - s1, err := c1.OpenStream() - checkErr(t, err) - defer s1.Close() - - buf1 := randBuf(4096) - log("writing %d bytes to stream", len(buf1)) - _, err = s1.Write(buf1) - checkErr(t, err) - - buf2 := make([]byte, len(buf1)) - log("reading %d bytes from stream (echoed)", len(buf2)) - _, err = s1.Read(buf2) - checkErr(t, err) - - if string(buf2) != string(buf1) { - t.Error("buf1 and buf2 not equal: %s != %s", string(buf1), string(buf2)) - } - log("done") -} - -func SubtestStress(t *testing.T, opt Options) { - - msgsize := 1 << 11 - errs := make(chan error, 0) // dont block anything. - - rateLimitN := 5000 // max of 5k funcs, because -race has 8k max. - rateLimitChan := make(chan struct{}, rateLimitN) - for i := 0; i < rateLimitN; i++ { - rateLimitChan <- struct{}{} - } - - rateLimit := func(f func()) { - <-rateLimitChan - f() - rateLimitChan <- struct{}{} - } - - writeStream := func(s smux.Stream, bufs chan<- []byte) { - log("writeStream %p, %d msgNum", s, opt.msgNum) - - for i := 0; i < opt.msgNum; i++ { - buf := randBuf(msgsize) - bufs <- buf - log("%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, opt.msgNum, buf[:3]) - if _, err := s.Write(buf); err != nil { - errs <- fmt.Errorf("s.Write(buf): %s", err) - continue - } - } - } - - readStream := func(s smux.Stream, bufs <-chan []byte) { - log("readStream %p, %d msgNum", s, opt.msgNum) - - buf2 := make([]byte, msgsize) - i := 0 - for buf1 := range bufs { - i++ - log("%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3]) - - if _, err := io.ReadFull(s, buf2); err != nil { - errs <- fmt.Errorf("io.ReadFull(s, buf2): %s", err) - log("%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.msgNum, buf1[:3]) - continue - } - if !bytes.Equal(buf1, buf2) { - errs <- fmt.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3]) - } - } - } - - openStreamAndRW := func(c smux.Conn) { - log("openStreamAndRW %p, %d opt.msgNum", c, opt.msgNum) - - s, err := c.OpenStream() - if err != nil { - errs <- fmt.Errorf("Failed to create NewStream: %s", err) - return - } - - bufs := make(chan []byte, opt.msgNum) - go func() { - writeStream(s, bufs) - close(bufs) - }() - - readStream(s, bufs) - s.Close() - } - - openConnAndRW := func() { - log("openConnAndRW") - - l, err := net.Listen("tcp", "localhost:0") - checkErr(t, err) - done := GoServe(t, opt.tr, l) - defer done() - - nla := l.Addr() - nc, err := net.Dial(nla.Network(), nla.String()) - checkErr(t, err) - if err != nil { - t.Fatal(fmt.Errorf("net.Dial(%s, %s): %s", nla.Network(), nla.String(), err)) - return - } - - c, err := opt.tr.NewConn(nc, false) - if err != nil { - t.Fatal(fmt.Errorf("a.AddConn(%s <--> %s): %s", nc.LocalAddr(), nc.RemoteAddr(), err)) - return - } - - // serve the outgoing conn, because some muxers assume - // that we _always_ call serve. (this is an error?) - go c.Serve(func(s smux.Stream) { - log("serving connection") - echoStream(s) - s.Close() - }) - - var wg sync.WaitGroup - for i := 0; i < opt.streamNum; i++ { - wg.Add(1) - go rateLimit(func() { - defer wg.Done() - openStreamAndRW(c) - }) - } - wg.Wait() - c.Close() - } - - openConnsAndRW := func() { - log("openConnsAndRW, %d conns", opt.connNum) - - var wg sync.WaitGroup - for i := 0; i < opt.connNum; i++ { - wg.Add(1) - go rateLimit(func() { - defer wg.Done() - openConnAndRW() - }) - } - wg.Wait() - } - - go func() { - openConnsAndRW() - close(errs) // done - }() - - for err := range errs { - t.Error(err) - } - -} - -func SubtestStress1Conn1Stream1Msg(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 1, - streamNum: 1, - msgNum: 1, - msgMax: 100, - msgMin: 100, - }) -} - -func SubtestStress1Conn1Stream100Msg(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 1, - streamNum: 1, - msgNum: 100, - msgMax: 100, - msgMin: 100, - }) -} - -func SubtestStress1Conn100Stream100Msg(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 1, - streamNum: 100, - msgNum: 100, - msgMax: 100, - msgMin: 100, - }) -} - -func SubtestStress50Conn10Stream50Msg(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 50, - streamNum: 10, - msgNum: 50, - msgMax: 100, - msgMin: 100, - }) -} - -func SubtestStress1Conn1000Stream10Msg(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 1, - streamNum: 1000, - msgNum: 10, - msgMax: 100, - msgMin: 100, - }) -} - -func SubtestStress1Conn100Stream100Msg10MB(t *testing.T, tr smux.Transport) { - SubtestStress(t, Options{ - tr: tr, - connNum: 1, - streamNum: 100, - msgNum: 100, - msgMax: 10000, - msgMin: 1000, - }) -} - -func SubtestAll(t *testing.T, tr smux.Transport) { - - tests := []TransportTest{ - SubtestSimpleWrite, - SubtestStress1Conn1Stream1Msg, - SubtestStress1Conn1Stream100Msg, - SubtestStress1Conn100Stream100Msg, - SubtestStress50Conn10Stream50Msg, - SubtestStress1Conn1000Stream10Msg, - SubtestStress1Conn100Stream100Msg10MB, - } - - for _, f := range tests { - if testing.Verbose() { - fmt.Fprintf(os.Stderr, "==== RUN %s\n", GetFunctionName(f)) - } - f(t, tr) - } -} - -type TransportTest func(t *testing.T, tr smux.Transport) - -func TestNoOp(t *testing.T) {} - -func GetFunctionName(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux.go deleted file mode 100644 index 29884e2e2..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux.go +++ /dev/null @@ -1,100 +0,0 @@ -package sm_yamux - -import ( - "io/ioutil" - "net" - "time" - - yamux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/yamux" - smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" -) - -// stream implements smux.Stream using a ss.Stream -type stream yamux.Stream - -func (s *stream) yamuxStream() *yamux.Stream { - return (*yamux.Stream)(s) -} - -func (s *stream) Read(buf []byte) (int, error) { - return s.yamuxStream().Read(buf) -} - -func (s *stream) Write(buf []byte) (int, error) { - return s.yamuxStream().Write(buf) -} - -func (s *stream) Close() error { - return s.yamuxStream().Close() -} - -// Conn is a connection to a remote peer. -type conn yamux.Session - -func (c *conn) yamuxSession() *yamux.Session { - return (*yamux.Session)(c) -} - -func (c *conn) Close() error { - return c.yamuxSession().Close() -} - -func (c *conn) IsClosed() bool { - return c.yamuxSession().IsClosed() -} - -// OpenStream creates a new stream. -func (c *conn) OpenStream() (smux.Stream, error) { - s, err := c.yamuxSession().OpenStream() - if err != nil { - return nil, err - } - - return (*stream)(s), nil -} - -// AcceptStream accepts a stream opened by the other side. -func (c *conn) AcceptStream() (smux.Stream, error) { - s, err := c.yamuxSession().AcceptStream() - return (*stream)(s), err -} - -// Serve starts listening for incoming requests and handles them -// using given StreamHandler -func (c *conn) Serve(handler smux.StreamHandler) { - for { // accept loop - s, err := c.AcceptStream() - if err != nil { - return // err always means closed. - } - go handler(s) - } -} - -// Transport is a go-peerstream transport that constructs -// yamux-backed connections. -type Transport yamux.Config - -// DefaultTransport has default settings for yamux -var DefaultTransport = (*Transport)(&yamux.Config{ - AcceptBacklog: 256, // from yamux.DefaultConfig - EnableKeepAlive: true, // from yamux.DefaultConfig - KeepAliveInterval: 30 * time.Second, // from yamux.DefaultConfig - MaxStreamWindowSize: uint32(256 * 1024), // from yamux.DefaultConfig - LogOutput: ioutil.Discard, -}) - -func (t *Transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) { - var s *yamux.Session - var err error - if isServer { - s, err = yamux.Server(nc, t.Config()) - } else { - s, err = yamux.Client(nc, t.Config()) - } - return (*conn)(s), err -} - -func (t *Transport) Config() *yamux.Config { - return (*yamux.Config)(t) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux_test.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux_test.go deleted file mode 100644 index 9e699bf4a..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/yamux/yamux_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package sm_yamux - -import ( - "testing" - - test "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/test" -) - -func TestYamuxTransport(t *testing.T) { - test.SubtestAll(t, DefaultTransport) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml deleted file mode 100644 index 7b571f400..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.3 - - release - - tip - -script: - - go test -race -cpu=5 -v ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/LICENSE b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/LICENSE deleted file mode 100644 index c7386b3c9..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Juan Batiz-Benet - -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. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/README.md b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/README.md deleted file mode 100644 index acd4cf536..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# go-temp-err-catcher - -This is a little package to use with your net.Listeners. - -Docs: https://godoc.org/github.com/jbenet/go-temp-err-catcher - -Get: - - go get github.com/jbenet/go-temp-err-catcher - -## Examples - -It is meant to be used with things like net.Lister.Accept: - -```go -import ( - tec "github.com/jbenet/go-temp-err-catcher" -) - -func listen(listener net.Listener) { - var c tec.TempErrCatcher - - for { - conn, err := listener.Accept() - if err != nil && c.IsTemporary(c) { - continue - } - return conn, err - } -} -``` - -You can make your errors implement `Temporary`: - -```go -type errTemp struct { - e error -} - -func (e errTemp) Temporary() bool { - return true -} - -func (e errTemp) Error() string { - return e.e.Error() -} - -err := errors.New("beep boop") -var c tec.TempErrCatcher -c.IsTemporary(err) // false -c.IsTemporary(errTemp{err}) // true -``` - -Or just use `ErrTemp`: - -```go -err := errors.New("beep boop") -var c tec.TempErrCatcher -c.IsTemporary(err) // false -c.IsTemporary(tec.ErrTemp{err}) // true -``` - - -You can also define an `IsTemp` function to classify errors: - -```go -var ErrSkip = errors.New("this should be skipped") -var ErrNotSkip = errors.New("this should not be skipped") - -var c tec.TempErrCatcher -c.IsTemp = func(e error) bool { - return e == ErrSkip -} - -c.IsTemporary(ErrSkip) // true -c.IsTemporary(ErrNotSkip) // false -c.IsTemporary(ErrTemp) // false! no longer accepts Temporary() -``` diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/doc.go b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/doc.go deleted file mode 100644 index 766c8b6f7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/doc.go +++ /dev/null @@ -1,62 +0,0 @@ -// Package temperrcatcher provides a TempErrCatcher object, -// which implements simple error-retrying functionality. -// It is meant to be used with things like net.Lister.Accept: -// -// import ( -// tec "github.com/jbenet/go-temp-err-catcher" -// ) -// -// func listen(listener net.Listener) { -// var c tec.TempErrCatcher -// -// for { -// conn, err := listener.Accept() -// if err != nil && c.IsTemporary(c) { -// continue -// } -// return conn, err -// } -// } -// -// You can make your errors implement `Temporary`: -// -// type errTemp struct { -// e error -// } -// -// func (e errTemp) Temporary() bool { -// return true -// } -// -// func (e errTemp) Error() string { -// return e.e.Error() -// } -// -// err := errors.New("beep boop") -// var c tec.TempErrCatcher -// c.IsTemporary(err) // false -// c.IsTemporary(errTemp{err}) // true -// -// Or just use `ErrTemp`: -// -// err := errors.New("beep boop") -// var c tec.TempErrCatcher -// c.IsTemporary(err) // false -// c.IsTemporary(tec.ErrTemp{err}) // true -// -// -// You can also define an `IsTemp` function to classify errors: -// -// var ErrSkip = errors.New("this should be skipped") -// var ErrNotSkip = errors.New("this should not be skipped") -// -// var c tec.TempErrCatcher -// c.IsTemp = func(e error) bool { -// return e == ErrSkip -// } -// -// c.IsTemporary(ErrSkip) // true -// c.IsTemporary(ErrNotSkip) // false -// c.IsTemporary(ErrTemp) // false! no longer accepts Temporary() -// -package temperrcatcher diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/example/example.go b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/example/example.go deleted file mode 100644 index 24dccd7e7..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/example/example.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "fmt" - - tec "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher" -) - -var ( - ErrTemp = tec.ErrTemporary{fmt.Errorf("ErrTemp")} - ErrSkip = fmt.Errorf("ErrSkip") - ErrOther = fmt.Errorf("ErrOther") -) - -func main() { - var normal tec.TempErrCatcher - var skipper tec.TempErrCatcher - skipper.IsTemp = func(e error) bool { - return e == ErrSkip - } - - fmt.Println("trying normal (uses Temporary interface)") - tryTec(normal) - fmt.Println("") - fmt.Println("trying skipper (uses our IsTemp function)") - tryTec(skipper) -} - -func tryTec(c tec.TempErrCatcher) { - errs := []error{ - ErrTemp, - ErrSkip, - ErrOther, - ErrTemp, - ErrSkip, - ErrOther, - } - - for _, e := range errs { - if c.IsTemporary(e) { - fmt.Printf("\tIsTemporary: true - skipped %s\n", e) - continue - } - - fmt.Printf("\tIsTemporary: false - not skipped %s\n", e) - } -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go deleted file mode 100644 index 1cd135c8f..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go +++ /dev/null @@ -1,172 +0,0 @@ -package temperrcatcher - -import ( - "fmt" - "testing" - "time" -) - -var ( - ErrTemp = ErrTemporary{fmt.Errorf("ErrTemp")} - ErrSkip = fmt.Errorf("ErrSkip") - ErrOther = fmt.Errorf("ErrOther") -) - -func testTec(t *testing.T, c TempErrCatcher, errs map[error]bool) { - for e, expected := range errs { - if c.IsTemporary(e) != expected { - t.Error("expected %s to be %v", e, expected) - } - } -} - -func TestNil(t *testing.T) { - var c TempErrCatcher - testTec(t, c, map[error]bool{ - ErrTemp: true, - ErrSkip: false, - ErrOther: false, - }) -} - -func TestWait(t *testing.T) { - var c TempErrCatcher - worked := make(chan time.Duration, 3) - c.Wait = func(t time.Duration) { - worked <- t - } - testTec(t, c, map[error]bool{ - ErrTemp: true, - ErrSkip: false, - ErrOther: false, - }) - - // should've called it once - select { - case <-worked: - default: - t.Error("did not call our Wait func") - } - - // should've called it ONLY once - select { - case <-worked: - t.Error("called our Wait func more than once") - default: - } -} - -func TestTemporary(t *testing.T) { - var c TempErrCatcher - testTec(t, c, map[error]bool{ - ErrTemp: true, - ErrSkip: false, - ErrOther: false, - }) -} - -func TestDoubles(t *testing.T) { - last := time.Now() - diff := func() time.Duration { - now := time.Now() - diff := now.Sub(last) - last = now - return diff - } - - testDiff := func(low, hi time.Duration) { - d := diff() - grace := time.Duration(50 * time.Microsecond) - if (d + grace) < low { - t.Error("time difference is smaller than", low, d) - } - if (d - grace) > hi { - t.Error("time difference is greater than", hi, d) - } - } - - var c TempErrCatcher - testDiff(0, c.Start) - c.IsTemporary(ErrTemp) - testDiff(c.Start, 2*c.Start) // first time. - c.IsTemporary(ErrTemp) - testDiff(2*c.Start, 4*c.Start) // second time. - c.IsTemporary(ErrTemp) - testDiff(4*c.Start, 8*c.Start) // third time. -} - -func TestDifferentStart(t *testing.T) { - last := time.Now() - diff := func() time.Duration { - now := time.Now() - diff := now.Sub(last) - last = now - return diff - } - - testDiff := func(low, hi time.Duration) { - d := diff() - grace := time.Duration(50 * time.Microsecond) - if (d + grace) < low { - t.Error("time difference is smaller than", low, d) - } - if (d - grace) > hi { - t.Error("time difference is greater than", hi, d) - } - } - - var c TempErrCatcher - f := time.Millisecond - testDiff(0, f) - c.IsTemporary(ErrTemp) - testDiff(f, 2*f) // first time. - c.IsTemporary(ErrTemp) - testDiff(2*f, 4*f) // second time. - c.IsTemporary(ErrTemp) - testDiff(4*f, 8*f) // third time. - - c.Reset() - c.Start = 10 * time.Millisecond - f = c.Start - testDiff(0, f) - c.IsTemporary(ErrTemp) - testDiff(f, 2*f) // first time. - c.IsTemporary(ErrTemp) - testDiff(2*f, 4*f) // second time. - c.IsTemporary(ErrTemp) - testDiff(4*f, 8*f) // third time. -} - -func TestDifferentStreaks(t *testing.T) { - var c TempErrCatcher - // one streak - c.IsTemporary(ErrTemp) // 1 - c.IsTemporary(ErrTemp) // 2 - c.IsTemporary(ErrTemp) // 4 - expect := 4 * time.Millisecond - if c.delay != expect { - t.Error("delay should be:", expect, c.delay) - } - - <-time.After(c.delay * 10) - - // a different streak - c.IsTemporary(ErrTemp) // 1 - c.IsTemporary(ErrTemp) // 2 - c.IsTemporary(ErrTemp) // 4 - if c.delay != expect { - t.Error("delay should be:", expect, c.delay) - } -} - -func TestFunc(t *testing.T) { - var c TempErrCatcher - c.IsTemp = func(e error) bool { - return e == ErrSkip - } - testTec(t, c, map[error]bool{ - ErrTemp: false, - ErrSkip: true, - ErrOther: false, - }) -} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go b/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go deleted file mode 100644 index fe8e780c6..000000000 --- a/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go +++ /dev/null @@ -1,124 +0,0 @@ -// Package temperrcatcher provides a TempErrCatcher object, -// which implements simple error-retrying functionality. -package temperrcatcher - -import ( - "time" -) - -// InitialDelay governs how long to wait the first time. -// This is defaulted to time.Millisecond, which makes sense -// for network listener failures. You may want a much smaller -// delay. You can configure this package wide, or in each -// TempErrCatcher -var InitialDelay = time.Millisecond - -// Temporary is an interface errors can implement to -// ensure they are correctly classified by the default -// TempErrCatcher classifier -type Temporary interface { - Temporary() bool -} - -// ErrIsTemporary returns whether an error is Temporary(), -// iff it implements the Temporary interface. -func ErrIsTemporary(e error) bool { - te, ok := e.(Temporary) - return ok && te.Temporary() -} - -// TempErrCatcher catches temporary errors for you. It then sleeps -// for a bit before returning (you should then try again). This may -// seem odd, but it's exactly what net/http does: -// http://golang.org/src/net/http/server.go?s=51504:51550#L1728 -// -// You can set a few options in TempErrCatcher. They all have defaults -// so a zero TempErrCatcher is ready to be used: -// -// var c tec.TempErrCatcher -// c.IsTemporary(tempErr) -// -type TempErrCatcher struct { - IsTemp func(error) bool // the classifier to use. default: ErrIsTemporary - Wait func(time.Duration) // the wait func to call. default: time.Sleep - Max time.Duration // the maximum time to wait. default: time.Second - Start time.Duration // the delay to start with. default: InitialDelay - delay time.Duration - last time.Time -} - -func (tec *TempErrCatcher) init() { - if tec.Max == 0 { - tec.Max = time.Second - } - if tec.IsTemp == nil { - tec.IsTemp = ErrIsTemporary - } - if tec.Wait == nil { - tec.Wait = time.Sleep - } - if tec.Start == 0 { - tec.Start = InitialDelay - } -} - -// IsTemporary checks whether an error is temporary. It will call -// tec.Wait before returning, with a delay. The delay is also -// doubled, so we do not constantly spin. This is the strategy -// net.Listener uses. -// -// Note: you will want to call Reset() if you get a success, -// so that the stored delay is brough back to 0. -func (tec *TempErrCatcher) IsTemporary(e error) bool { - tec.init() - if tec.IsTemp(e) { - now := time.Now() - if now.Sub(tec.last) > (tec.delay * 5) { - // this is a "new streak" of temp failures. reset. - tec.Reset() - } - - if tec.delay == 0 { // init case. - tec.delay = tec.Start - } else { - tec.delay *= 2 - } - - if tec.delay > tec.Max { - tec.delay = tec.Max - } - tec.Wait(tec.delay) - tec.last = now - return true - } - tec.Reset() // different failure. call reset - return false -} - -// Reset sets the internal delay counter to 0 -func (tec *TempErrCatcher) Reset() { - tec.delay = 0 -} - -// ErrTemporary wraps any error and implements Temporary function. -// -// err := errors.New("beep boop") -// var c tec.TempErrCatcher -// c.IsTemporary(err) // false -// c.IsTemporary(tec.ErrTemp{err}) // true -// -type ErrTemporary struct { - Err error -} - -func (e ErrTemporary) Temporary() bool { - return true -} - -func (e ErrTemporary) Error() string { - return e.Err.Error() -} - -func (e ErrTemporary) String() string { - return e.Error() -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/.gitignore b/Godeps/_workspace/src/github.com/miekg/dns/.gitignore deleted file mode 100644 index 776cd950c..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.6 -tags -test.out -a.out diff --git a/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml b/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml deleted file mode 100644 index f0a9d223c..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: go -go: - - 1.3 - - 1.4 -script: - - go test -short -bench=. diff --git a/Godeps/_workspace/src/github.com/miekg/dns/AUTHORS b/Godeps/_workspace/src/github.com/miekg/dns/AUTHORS deleted file mode 100644 index 196568352..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Miek Gieben diff --git a/Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS b/Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS deleted file mode 100644 index f77e8a895..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS +++ /dev/null @@ -1,9 +0,0 @@ -Alex A. Skinner -Andrew Tunnell-Jones -Ask Bjørn Hansen -Dave Cheney -Dusty Wilson -Marek Majkowski -Peter van Dijk -Omri Bahumi -Alex Sergeyev diff --git a/Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT b/Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT deleted file mode 100644 index 35702b10e..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT +++ /dev/null @@ -1,9 +0,0 @@ -Copyright 2009 The Go Authors. All rights reserved. Use of this source code -is governed by a BSD-style license that can be found in the LICENSE file. -Extensions of the original work are copyright (c) 2011 Miek Gieben - -Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is -governed by a BSD-style license that can be found in the LICENSE file. - -Copyright 2014 CloudFlare. All rights reserved. Use of this source code is -governed by a BSD-style license that can be found in the LICENSE file. diff --git a/Godeps/_workspace/src/github.com/miekg/dns/LICENSE b/Godeps/_workspace/src/github.com/miekg/dns/LICENSE deleted file mode 100644 index 5763fa7fe..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -Extensions of the original work are copyright (c) 2011 Miek Gieben - -As this is fork of the official Go code the same license applies: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/Godeps/_workspace/src/github.com/miekg/dns/README.md b/Godeps/_workspace/src/github.com/miekg/dns/README.md deleted file mode 100644 index b09cb4cf1..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/README.md +++ /dev/null @@ -1,143 +0,0 @@ -[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns) - -# Alternative (more granular) approach to a DNS library - -> Less is more. - -Complete and usable DNS library. All widely used Resource Records are -supported, including the DNSSEC types. It follows a lean and mean philosophy. -If there is stuff you should know as a DNS programmer there isn't a convenience -function for it. Server side and client side programming is supported, i.e. you -can build servers and resolvers with it. - -If you like this, you may also be interested in: - -* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver. - -# Goals - -* KISS; -* Fast; -* Small API, if its easy to code in Go, don't make a function for it. - -# Users - -A not-so-up-to-date-list-that-may-be-actually-current: - -* https://github.com/abh/geodns -* http://www.statdns.com/ -* http://www.dnsinspect.com/ -* https://github.com/chuangbo/jianbing-dictionary-dns -* http://www.dns-lg.com/ -* https://github.com/fcambus/rrda -* https://github.com/kenshinx/godns -* https://github.com/skynetservices/skydns -* https://github.com/DevelopersPL/godnsagent -* https://github.com/duedil-ltd/discodns -* https://github.com/StalkR/dns-reverse-proxy -* https://github.com/tianon/rawdns -* https://mesosphere.github.io/mesos-dns/ - -Send pull request if you want to be listed here. - -# Features - -* UDP/TCP queries, IPv4 and IPv6; -* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported; -* Fast: - * Reply speed around ~ 80K qps (faster hardware results in more qps); - * Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds; -* Server side programming (mimicking the net/http package); -* Client side programming; -* DNSSEC: signing, validating and key generation for DSA, RSA and ECDSA; -* EDNS0, NSID; -* AXFR/IXFR; -* TSIG, SIG(0); -* DNS name compression; -* Depends only on the standard library. - -Have fun! - -Miek Gieben - 2010-2012 - - -# Building - -Building is done with the `go` tool. If you have setup your GOPATH -correctly, the following should work: - - go get github.com/miekg/dns - go build github.com/miekg/dns - -## Examples - -A short "how to use the API" is at the beginning of doc.go (this also will show -when you call `godoc github.com/miekg/dns`). - -Example programs can be found in the `github.com/miekg/exdns` repository. - -## Supported RFCs - -*all of them* - -* 103{4,5} - DNS standard -* 1348 - NSAP record -* 1982 - Serial Arithmetic -* 1876 - LOC record -* 1995 - IXFR -* 1996 - DNS notify -* 2136 - DNS Update (dynamic updates) -* 2181 - RRset definition - there is no RRset type though, just []RR -* 2537 - RSAMD5 DNS keys -* 2065 - DNSSEC (updated in later RFCs) -* 2671 - EDNS record -* 2782 - SRV record -* 2845 - TSIG record -* 2915 - NAPTR record -* 2929 - DNS IANA Considerations -* 3110 - RSASHA1 DNS keys -* 3225 - DO bit (DNSSEC OK) -* 340{1,2,3} - NAPTR record -* 3445 - Limiting the scope of (DNS)KEY -* 3597 - Unknown RRs -* 4025 - IPSECKEY -* 403{3,4,5} - DNSSEC + validation functions -* 4255 - SSHFP record -* 4343 - Case insensitivity -* 4408 - SPF record -* 4509 - SHA256 Hash in DS -* 4592 - Wildcards in the DNS -* 4635 - HMAC SHA TSIG -* 4701 - DHCID -* 4892 - id.server -* 5001 - NSID -* 5155 - NSEC3 record -* 5205 - HIP record -* 5702 - SHA2 in the DNS -* 5936 - AXFR -* 5966 - TCP implementation recommendations -* 6605 - ECDSA -* 6725 - IANA Registry Update -* 6742 - ILNP DNS -* 6891 - EDNS0 update -* 6895 - DNS IANA considerations -* 6975 - Algorithm Understanding in DNSSEC -* 7043 - EUI48/EUI64 records -* 7314 - DNS (EDNS) EXPIRE Option -* xxxx - URI record (draft) -* xxxx - EDNS0 DNS Update Lease (draft) - -## Loosely based upon - -* `ldns` -* `NSD` -* `Net::DNS` -* `GRONG` - -## TODO - -* privatekey.Precompute() when signing? -* Last remaining RRs: APL, ATMA, A6 and NXT and IPSECKEY; -* Missing in parsing: ISDN, UNSPEC, ATMA; -* CAA parsing is broken; -* NSEC(3) cover/match/closest enclose; -* Replies with TC bit are not parsed to the end; diff --git a/Godeps/_workspace/src/github.com/miekg/dns/client.go b/Godeps/_workspace/src/github.com/miekg/dns/client.go deleted file mode 100644 index cdab4432a..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/client.go +++ /dev/null @@ -1,326 +0,0 @@ -package dns - -// A client implementation. - -import ( - "bytes" - "io" - "net" - "time" -) - -const dnsTimeout time.Duration = 2 * time.Second -const tcpIdleTimeout time.Duration = 8 * time.Second - -// A Conn represents a connection to a DNS server. -type Conn struct { - net.Conn // a net.Conn holding the connection - UDPSize uint16 // minimum receive buffer for UDP messages - TsigSecret map[string]string // secret(s) for Tsig map[], zonename must be fully qualified - rtt time.Duration - t time.Time - tsigRequestMAC string -} - -// A Client defines parameters for a DNS client. -type Client struct { - Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) - UDPSize uint16 // minimum receive buffer for UDP messages - DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds - ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - TsigSecret map[string]string // secret(s) for Tsig map[], zonename must be fully qualified - SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass - group singleflight -} - -// Exchange performs a synchronous UDP query. It sends the message m to the address -// contained in a and waits for an reply. Exchange does not retry a failed query, nor -// will it fall back to TCP in case of truncation. -// If you need to send a DNS message on an already existing connection, you can use the -// following: -// -// co := &dns.Conn{Conn: c} // c is your net.Conn -// co.WriteMsg(m) -// in, err := co.ReadMsg() -// co.Close() -// -func Exchange(m *Msg, a string) (r *Msg, err error) { - var co *Conn - co, err = DialTimeout("udp", a, dnsTimeout) - if err != nil { - return nil, err - } - - defer co.Close() - co.SetReadDeadline(time.Now().Add(dnsTimeout)) - co.SetWriteDeadline(time.Now().Add(dnsTimeout)) - - opt := m.IsEdns0() - // If EDNS0 is used use that for size. - if opt != nil && opt.UDPSize() >= MinMsgSize { - co.UDPSize = opt.UDPSize() - } - - if err = co.WriteMsg(m); err != nil { - return nil, err - } - r, err = co.ReadMsg() - return r, err -} - -// ExchangeConn performs a synchronous query. It sends the message m via the connection -// c and waits for a reply. The connection c is not closed by ExchangeConn. -// This function is going away, but can easily be mimicked: -// -// co := &dns.Conn{Conn: c} // c is your net.Conn -// co.WriteMsg(m) -// in, _ := co.ReadMsg() -// co.Close() -// -func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { - println("dns: this function is deprecated") - co := new(Conn) - co.Conn = c - if err = co.WriteMsg(m); err != nil { - return nil, err - } - r, err = co.ReadMsg() - return r, err -} - -// Exchange performs an synchronous query. It sends the message m to the address -// contained in a and waits for an reply. Basic use pattern with a *dns.Client: -// -// c := new(dns.Client) -// in, rtt, err := c.Exchange(message, "127.0.0.1:53") -// -// Exchange does not retry a failed query, nor will it fall back to TCP in -// case of truncation. -func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { - if !c.SingleInflight { - return c.exchange(m, a) - } - // This adds a bunch of garbage, TODO(miek). - t := "nop" - if t1, ok := TypeToString[m.Question[0].Qtype]; ok { - t = t1 - } - cl := "nop" - if cl1, ok := ClassToString[m.Question[0].Qclass]; ok { - cl = cl1 - } - r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) { - return c.exchange(m, a) - }) - if err != nil { - return r, rtt, err - } - if shared { - return r.Copy(), rtt, nil - } - return r, rtt, nil -} - -func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { - timeout := dnsTimeout - var co *Conn - if c.DialTimeout != 0 { - timeout = c.DialTimeout - } - if c.Net == "" { - co, err = DialTimeout("udp", a, timeout) - } else { - co, err = DialTimeout(c.Net, a, timeout) - } - if err != nil { - return nil, 0, err - } - timeout = dnsTimeout - if c.ReadTimeout != 0 { - timeout = c.ReadTimeout - } - co.SetReadDeadline(time.Now().Add(timeout)) - timeout = dnsTimeout - if c.WriteTimeout != 0 { - timeout = c.WriteTimeout - } - co.SetWriteDeadline(time.Now().Add(timeout)) - defer co.Close() - opt := m.IsEdns0() - // If EDNS0 is used use that for size. - if opt != nil && opt.UDPSize() >= MinMsgSize { - co.UDPSize = opt.UDPSize() - } - // Otherwise use the client's configured UDP size. - if opt == nil && c.UDPSize >= MinMsgSize { - co.UDPSize = c.UDPSize - } - co.TsigSecret = c.TsigSecret - if err = co.WriteMsg(m); err != nil { - return nil, 0, err - } - r, err = co.ReadMsg() - return r, co.rtt, err -} - -// ReadMsg reads a message from the connection co. -// If the received message contains a TSIG record the transaction -// signature is verified. -func (co *Conn) ReadMsg() (*Msg, error) { - var p []byte - m := new(Msg) - if _, ok := co.Conn.(*net.TCPConn); ok { - p = make([]byte, MaxMsgSize) - } else { - if co.UDPSize >= 512 { - p = make([]byte, co.UDPSize) - } else { - p = make([]byte, MinMsgSize) - } - } - n, err := co.Read(p) - if err != nil && n == 0 { - return nil, err - } - p = p[:n] - if err := m.Unpack(p); err != nil { - return nil, err - } - co.rtt = time.Since(co.t) - if t := m.IsTsig(); t != nil { - if _, ok := co.TsigSecret[t.Hdr.Name]; !ok { - return m, ErrSecret - } - // Need to work on the original message p, as that was used to calculate the tsig. - err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false) - } - return m, err -} - -// Read implements the net.Conn read method. -func (co *Conn) Read(p []byte) (n int, err error) { - if co.Conn == nil { - return 0, ErrConnEmpty - } - if len(p) < 2 { - return 0, io.ErrShortBuffer - } - if t, ok := co.Conn.(*net.TCPConn); ok { - n, err = t.Read(p[0:2]) - if err != nil || n != 2 { - return n, err - } - l, _ := unpackUint16(p[0:2], 0) - if l == 0 { - return 0, ErrShortRead - } - if int(l) > len(p) { - return int(l), io.ErrShortBuffer - } - n, err = t.Read(p[:l]) - if err != nil { - return n, err - } - i := n - for i < int(l) { - j, err := t.Read(p[i:int(l)]) - if err != nil { - return i, err - } - i += j - } - n = i - return n, err - } - // UDP connection - n, err = co.Conn.Read(p) - if err != nil { - return n, err - } - return n, err -} - -// WriteMsg sends a message throught the connection co. -// If the message m contains a TSIG record the transaction -// signature is calculated. -func (co *Conn) WriteMsg(m *Msg) (err error) { - var out []byte - if t := m.IsTsig(); t != nil { - mac := "" - if _, ok := co.TsigSecret[t.Hdr.Name]; !ok { - return ErrSecret - } - out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false) - // Set for the next read, allthough only used in zone transfers - co.tsigRequestMAC = mac - } else { - out, err = m.Pack() - } - if err != nil { - return err - } - co.t = time.Now() - if _, err = co.Write(out); err != nil { - return err - } - return nil -} - -// Write implements the net.Conn Write method. -func (co *Conn) Write(p []byte) (n int, err error) { - if t, ok := co.Conn.(*net.TCPConn); ok { - lp := len(p) - if lp < 2 { - return 0, io.ErrShortBuffer - } - if lp > MaxMsgSize { - return 0, &Error{err: "message too large"} - } - l := make([]byte, 2, lp+2) - l[0], l[1] = packUint16(uint16(lp)) - p = append(l, p...) - n, err := io.Copy(t, bytes.NewReader(p)) - return int(n), err - } - n, err = co.Conn.(*net.UDPConn).Write(p) - return n, err -} - -// Dial connects to the address on the named network. -func Dial(network, address string) (conn *Conn, err error) { - conn = new(Conn) - conn.Conn, err = net.Dial(network, address) - if err != nil { - return nil, err - } - return conn, nil -} - -// DialTimeout acts like Dial but takes a timeout. -func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) { - conn = new(Conn) - conn.Conn, err = net.DialTimeout(network, address, timeout) - if err != nil { - return nil, err - } - return conn, nil -} - -// Close implements the net.Conn Close method. -func (co *Conn) Close() error { return co.Conn.Close() } - -// LocalAddr implements the net.Conn LocalAddr method. -func (co *Conn) LocalAddr() net.Addr { return co.Conn.LocalAddr() } - -// RemoteAddr implements the net.Conn RemoteAddr method. -func (co *Conn) RemoteAddr() net.Addr { return co.Conn.RemoteAddr() } - -// SetDeadline implements the net.Conn SetDeadline method. -func (co *Conn) SetDeadline(t time.Time) error { return co.Conn.SetDeadline(t) } - -// SetReadDeadline implements the net.Conn SetReadDeadline method. -func (co *Conn) SetReadDeadline(t time.Time) error { return co.Conn.SetReadDeadline(t) } - -// SetWriteDeadline implements the net.Conn SetWriteDeadline method. -func (co *Conn) SetWriteDeadline(t time.Time) error { return co.Conn.SetWriteDeadline(t) } diff --git a/Godeps/_workspace/src/github.com/miekg/dns/client_test.go b/Godeps/_workspace/src/github.com/miekg/dns/client_test.go deleted file mode 100644 index d0294f973..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/client_test.go +++ /dev/null @@ -1,214 +0,0 @@ -package dns - -import ( - "strconv" - "testing" - "time" -) - -func TestClientSync(t *testing.T) { - HandleFunc("miek.nl.", HelloServer) - defer HandleRemove("miek.nl.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - m := new(Msg) - m.SetQuestion("miek.nl.", TypeSOA) - - c := new(Client) - r, _, err := c.Exchange(m, addrstr) - if err != nil { - t.Errorf("failed to exchange: %v", err) - } - if r != nil && r.Rcode != RcodeSuccess { - t.Errorf("failed to get an valid answer\n%v", r) - } - // And now with plain Exchange(). - r, err = Exchange(m, addrstr) - if err != nil { - t.Errorf("failed to exchange: %v", err) - } - if r != nil && r.Rcode != RcodeSuccess { - t.Errorf("failed to get an valid answer\n%v", r) - } -} - -func TestClientEDNS0(t *testing.T) { - HandleFunc("miek.nl.", HelloServer) - defer HandleRemove("miek.nl.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - m := new(Msg) - m.SetQuestion("miek.nl.", TypeDNSKEY) - - m.SetEdns0(2048, true) - - c := new(Client) - r, _, err := c.Exchange(m, addrstr) - if err != nil { - t.Errorf("failed to exchange: %v", err) - } - - if r != nil && r.Rcode != RcodeSuccess { - t.Errorf("failed to get an valid answer\n%v", r) - } -} - -// Validates the transmission and parsing of local EDNS0 options. -func TestClientEDNS0Local(t *testing.T) { - - optStr1 := "1979:0x0707" - optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601" - - handler := func(w ResponseWriter, req *Msg) { - m := new(Msg) - m.SetReply(req) - - m.Extra = make([]RR, 1, 2) - m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}} - - // If the local options are what we expect, then reflect them back. - ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String() - ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String() - if ec1 == optStr1 && ec2 == optStr2 { - m.Extra = append(m.Extra, req.Extra[0]) - } - - w.WriteMsg(m) - } - - HandleFunc("miek.nl.", handler) - defer HandleRemove("miek.nl.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %s", err) - } - defer s.Shutdown() - - m := new(Msg) - m.SetQuestion("miek.nl.", TypeTXT) - - // Add two local edns options to the query. - ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}} - ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}} - o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}} - m.Extra = append(m.Extra, o) - - c := new(Client) - r, _, e := c.Exchange(m, addrstr) - if e != nil { - t.Logf("failed to exchange: %s", e.Error()) - t.Fail() - } - - if r != nil && r.Rcode != RcodeSuccess { - t.Log("failed to get a valid answer") - t.Fail() - t.Logf("%v\n", r) - } - - txt := r.Extra[0].(*TXT).Txt[0] - if txt != "Hello local edns" { - t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns") - t.Fail() - } - - // Validate the local options in the reply. - got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String() - if got != optStr1 { - t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1) - t.Fail() - t.Logf("%v\n", r) - } - - got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String() - if got != optStr2 { - t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2) - t.Fail() - t.Logf("%v\n", r) - } -} - -func TestSingleSingleInflight(t *testing.T) { - HandleFunc("miek.nl.", HelloServer) - defer HandleRemove("miek.nl.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - m := new(Msg) - m.SetQuestion("miek.nl.", TypeDNSKEY) - - c := new(Client) - c.SingleInflight = true - nr := 10 - ch := make(chan time.Duration) - for i := 0; i < nr; i++ { - go func() { - _, rtt, _ := c.Exchange(m, addrstr) - ch <- rtt - }() - } - i := 0 - var first time.Duration - // With inflight *all* rtt are identical, and by doing actual lookups - // the changes that this is a coincidence is small. -Loop: - for { - select { - case rtt := <-ch: - if i == 0 { - first = rtt - } else { - if first != rtt { - t.Errorf("all rtts should be equal. got %d want %d", rtt, first) - } - } - i++ - if i == 10 { - break Loop - } - } - } -} - -// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG. -func ExampleUpdateLeaseTSIG(t *testing.T) { - m := new(Msg) - m.SetUpdate("t.local.ip6.io.") - rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1") - rrs := make([]RR, 1) - rrs[0] = rr - m.Insert(rrs) - - leaseRr := new(OPT) - leaseRr.Hdr.Name = "." - leaseRr.Hdr.Rrtype = TypeOPT - e := new(EDNS0_UL) - e.Code = EDNS0UL - e.Lease = 120 - leaseRr.Option = append(leaseRr.Option, e) - m.Extra = append(m.Extra, leaseRr) - - c := new(Client) - m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix()) - c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="} - - _, _, err := c.Exchange(m, "127.0.0.1:53") - if err != nil { - t.Error(err) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go b/Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go deleted file mode 100644 index cfa9ad0b2..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go +++ /dev/null @@ -1,99 +0,0 @@ -package dns - -import ( - "bufio" - "os" - "strconv" - "strings" -) - -// ClientConfig wraps the contents of the /etc/resolv.conf file. -type ClientConfig struct { - Servers []string // servers to use - Search []string // suffixes to append to local name - Port string // what port to use - Ndots int // number of dots in name to trigger absolute lookup - Timeout int // seconds before giving up on packet - Attempts int // lost packets before giving up on server, not used in the package dns -} - -// ClientConfigFromFile parses a resolv.conf(5) like file and returns -// a *ClientConfig. -func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) { - file, err := os.Open(resolvconf) - if err != nil { - return nil, err - } - defer file.Close() - c := new(ClientConfig) - scanner := bufio.NewScanner(file) - c.Servers = make([]string, 0) - c.Search = make([]string, 0) - c.Port = "53" - c.Ndots = 1 - c.Timeout = 5 - c.Attempts = 2 - - for scanner.Scan() { - if err := scanner.Err(); err != nil { - return nil, err - } - line := scanner.Text() - f := strings.Fields(line) - if len(f) < 1 { - continue - } - switch f[0] { - case "nameserver": // add one name server - if len(f) > 1 { - // One more check: make sure server name is - // just an IP address. Otherwise we need DNS - // to look it up. - name := f[1] - c.Servers = append(c.Servers, name) - } - - case "domain": // set search path to just this domain - if len(f) > 1 { - c.Search = make([]string, 1) - c.Search[0] = f[1] - } else { - c.Search = make([]string, 0) - } - - case "search": // set search path to given servers - c.Search = make([]string, len(f)-1) - for i := 0; i < len(c.Search); i++ { - c.Search[i] = f[i+1] - } - - case "options": // magic options - for i := 1; i < len(f); i++ { - s := f[i] - switch { - case len(s) >= 6 && s[:6] == "ndots:": - n, _ := strconv.Atoi(s[6:]) - if n < 1 { - n = 1 - } - c.Ndots = n - case len(s) >= 8 && s[:8] == "timeout:": - n, _ := strconv.Atoi(s[8:]) - if n < 1 { - n = 1 - } - c.Timeout = n - case len(s) >= 8 && s[:9] == "attempts:": - n, _ := strconv.Atoi(s[9:]) - if n < 1 { - n = 1 - } - c.Attempts = n - case s == "rotate": - /* not imp */ - } - } - } - } - return c, nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/clientconfig_test.go b/Godeps/_workspace/src/github.com/miekg/dns/clientconfig_test.go deleted file mode 100644 index f01a59be6..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/clientconfig_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package dns - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" -) - -const normal string = ` -# Comment -domain somedomain.com -nameserver 10.28.10.2 -nameserver 11.28.10.1 -` - -const missingNewline string = ` -domain somedomain.com -nameserver 10.28.10.2 -nameserver 11.28.10.1` // <- NOTE: NO newline. - -func testConfig(t *testing.T, data string) { - tempDir, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("TempDir: %v", err) - } - defer os.RemoveAll(tempDir) - - path := filepath.Join(tempDir, "resolv.conf") - if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil { - t.Fatalf("WriteFile: %v", err) - } - cc, err := ClientConfigFromFile(path) - if err != nil { - t.Errorf("error parsing resolv.conf: %v", err) - } - if l := len(cc.Servers); l != 2 { - t.Errorf("incorrect number of nameservers detected: %d", l) - } - if l := len(cc.Search); l != 1 { - t.Errorf("domain directive not parsed correctly: %v", cc.Search) - } else { - if cc.Search[0] != "somedomain.com" { - t.Errorf("domain is unexpected: %v", cc.Search[0]) - } - } -} - -func TestNameserver(t *testing.T) { - testConfig(t, normal) -} - -func TestMissingFinalNewLine(t *testing.T) { - testConfig(t, missingNewline) -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/defaults.go b/Godeps/_workspace/src/github.com/miekg/dns/defaults.go deleted file mode 100644 index 09331c9f6..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/defaults.go +++ /dev/null @@ -1,248 +0,0 @@ -package dns - -import ( - "errors" - "net" - "strconv" -) - -const hexDigit = "0123456789abcdef" - -// Everything is assumed in ClassINET. - -// SetReply creates a reply message from a request message. -func (dns *Msg) SetReply(request *Msg) *Msg { - dns.Id = request.Id - dns.RecursionDesired = request.RecursionDesired // Copy rd bit - dns.Response = true - dns.Opcode = OpcodeQuery - dns.Rcode = RcodeSuccess - if len(request.Question) > 0 { - dns.Question = make([]Question, 1) - dns.Question[0] = request.Question[0] - } - return dns -} - -// SetQuestion creates a question message, it sets the Question -// section, generates an Id and sets the RecursionDesired (RD) -// bit to true. -func (dns *Msg) SetQuestion(z string, t uint16) *Msg { - dns.Id = Id() - dns.RecursionDesired = true - dns.Question = make([]Question, 1) - dns.Question[0] = Question{z, t, ClassINET} - return dns -} - -// SetNotify creates a notify message, it sets the Question -// section, generates an Id and sets the Authoritative (AA) -// bit to true. -func (dns *Msg) SetNotify(z string) *Msg { - dns.Opcode = OpcodeNotify - dns.Authoritative = true - dns.Id = Id() - dns.Question = make([]Question, 1) - dns.Question[0] = Question{z, TypeSOA, ClassINET} - return dns -} - -// SetRcode creates an error message suitable for the request. -func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg { - dns.SetReply(request) - dns.Rcode = rcode - return dns -} - -// SetRcodeFormatError creates a message with FormError set. -func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg { - dns.Rcode = RcodeFormatError - dns.Opcode = OpcodeQuery - dns.Response = true - dns.Authoritative = false - dns.Id = request.Id - return dns -} - -// SetUpdate makes the message a dynamic update message. It -// sets the ZONE section to: z, TypeSOA, ClassINET. -func (dns *Msg) SetUpdate(z string) *Msg { - dns.Id = Id() - dns.Response = false - dns.Opcode = OpcodeUpdate - dns.Compress = false // BIND9 cannot handle compression - dns.Question = make([]Question, 1) - dns.Question[0] = Question{z, TypeSOA, ClassINET} - return dns -} - -// SetIxfr creates message for requesting an IXFR. -func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg { - dns.Id = Id() - dns.Question = make([]Question, 1) - dns.Ns = make([]RR, 1) - s := new(SOA) - s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0} - s.Serial = serial - s.Ns = ns - s.Mbox = mbox - dns.Question[0] = Question{z, TypeIXFR, ClassINET} - dns.Ns[0] = s - return dns -} - -// SetAxfr creates message for requesting an AXFR. -func (dns *Msg) SetAxfr(z string) *Msg { - dns.Id = Id() - dns.Question = make([]Question, 1) - dns.Question[0] = Question{z, TypeAXFR, ClassINET} - return dns -} - -// SetTsig appends a TSIG RR to the message. -// This is only a skeleton TSIG RR that is added as the last RR in the -// additional section. The Tsig is calculated when the message is being send. -func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg { - t := new(TSIG) - t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0} - t.Algorithm = algo - t.Fudge = 300 - t.TimeSigned = uint64(timesigned) - t.OrigId = dns.Id - dns.Extra = append(dns.Extra, t) - return dns -} - -// SetEdns0 appends a EDNS0 OPT RR to the message. -// TSIG should always the last RR in a message. -func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg { - e := new(OPT) - e.Hdr.Name = "." - e.Hdr.Rrtype = TypeOPT - e.SetUDPSize(udpsize) - if do { - e.SetDo() - } - dns.Extra = append(dns.Extra, e) - return dns -} - -// IsTsig checks if the message has a TSIG record as the last record -// in the additional section. It returns the TSIG record found or nil. -func (dns *Msg) IsTsig() *TSIG { - if len(dns.Extra) > 0 { - if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG { - return dns.Extra[len(dns.Extra)-1].(*TSIG) - } - } - return nil -} - -// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0 -// record in the additional section will do. It returns the OPT record -// found or nil. -func (dns *Msg) IsEdns0() *OPT { - for _, r := range dns.Extra { - if r.Header().Rrtype == TypeOPT { - return r.(*OPT) - } - } - return nil -} - -// IsDomainName checks if s is a valid domainname, it returns -// the number of labels and true, when a domain name is valid. -// Note that non fully qualified domain name is considered valid, in this case the -// last label is counted in the number of labels. -// When false is returned the number of labels is not defined. -func IsDomainName(s string) (labels int, ok bool) { - _, labels, err := packDomainName(s, nil, 0, nil, false) - return labels, err == nil -} - -// IsSubDomain checks if child is indeed a child of the parent. Both child and -// parent are *not* downcased before doing the comparison. -func IsSubDomain(parent, child string) bool { - // Entire child is contained in parent - return CompareDomainName(parent, child) == CountLabel(parent) -} - -// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet. -// The checking is performed on the binary payload. -func IsMsg(buf []byte) error { - // Header - if len(buf) < 12 { - return errors.New("dns: bad message header") - } - // Header: Opcode - // TODO(miek): more checks here, e.g. check all header bits. - return nil -} - -// IsFqdn checks if a domain name is fully qualified. -func IsFqdn(s string) bool { - l := len(s) - if l == 0 { - return false - } - return s[l-1] == '.' -} - -// Fqdn return the fully qualified domain name from s. -// If s is already fully qualified, it behaves as the identity function. -func Fqdn(s string) string { - if IsFqdn(s) { - return s - } - return s + "." -} - -// Copied from the official Go code. - -// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP -// address suitable for reverse DNS (PTR) record lookups or an error if it fails -// to parse the IP address. -func ReverseAddr(addr string) (arpa string, err error) { - ip := net.ParseIP(addr) - if ip == nil { - return "", &Error{err: "unrecognized address: " + addr} - } - if ip.To4() != nil { - return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." + - strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil - } - // Must be IPv6 - buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) - // Add it, in reverse, to the buffer - for i := len(ip) - 1; i >= 0; i-- { - v := ip[i] - buf = append(buf, hexDigit[v&0xF]) - buf = append(buf, '.') - buf = append(buf, hexDigit[v>>4]) - buf = append(buf, '.') - } - // Append "ip6.arpa." and return (buf already has the final .) - buf = append(buf, "ip6.arpa."...) - return string(buf), nil -} - -// String returns the string representation for the type t. -func (t Type) String() string { - if t1, ok := TypeToString[uint16(t)]; ok { - return t1 - } - return "TYPE" + strconv.Itoa(int(t)) -} - -// String returns the string representation for the class c. -func (c Class) String() string { - if c1, ok := ClassToString[uint16(c)]; ok { - return c1 - } - return "CLASS" + strconv.Itoa(int(c)) -} - -// String returns the string representation for the name n. -func (n Name) String() string { - return sprintName(string(n)) -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dns.go b/Godeps/_workspace/src/github.com/miekg/dns/dns.go deleted file mode 100644 index 1c37a09dd..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dns.go +++ /dev/null @@ -1,102 +0,0 @@ -package dns - -import "strconv" - -const ( - year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. - // DefaultMsgSize is the standard default for messages larger than 512 bytes. - DefaultMsgSize = 4096 - // MinMsgSize is the minimal size of a DNS packet. - MinMsgSize = 512 - // MaxMsgSize is the largest possible DNS packet. - MaxMsgSize = 65535 - defaultTtl = 3600 // Default internal TTL. -) - -// Error represents a DNS error -type Error struct{ err string } - -func (e *Error) Error() string { - if e == nil { - return "dns: " - } - return "dns: " + e.err -} - -// An RR represents a resource record. -type RR interface { - // Header returns the header of an resource record. The header contains - // everything up to the rdata. - Header() *RR_Header - // String returns the text representation of the resource record. - String() string - // copy returns a copy of the RR - copy() RR - // len returns the length (in octets) of the uncompressed RR in wire format. - len() int -} - -// DNS resource records. -// There are many types of RRs, -// but they all share the same header. -type RR_Header struct { - Name string `dns:"cdomain-name"` - Rrtype uint16 - Class uint16 - Ttl uint32 - Rdlength uint16 // length of data after header -} - -// Header returns itself. This is here to make RR_Header implement the RR interface. -func (h *RR_Header) Header() *RR_Header { return h } - -// Just to imlement the RR interface. -func (h *RR_Header) copy() RR { return nil } - -func (h *RR_Header) copyHeader() *RR_Header { - r := new(RR_Header) - r.Name = h.Name - r.Rrtype = h.Rrtype - r.Class = h.Class - r.Ttl = h.Ttl - r.Rdlength = h.Rdlength - return r -} - -func (h *RR_Header) String() string { - var s string - - if h.Rrtype == TypeOPT { - s = ";" - // and maybe other things - } - - s += sprintName(h.Name) + "\t" - s += strconv.FormatInt(int64(h.Ttl), 10) + "\t" - s += Class(h.Class).String() + "\t" - s += Type(h.Rrtype).String() + "\t" - return s -} - -func (h *RR_Header) len() int { - l := len(h.Name) + 1 - l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2) - return l -} - -// ToRFC3597 converts a known RR to the unknown RR representation -// from RFC 3597. -func (rr *RFC3597) ToRFC3597(r RR) error { - buf := make([]byte, r.len()*2) - off, err := PackStruct(r, buf, 0) - if err != nil { - return err - } - buf = buf[:off] - rawSetRdlength(buf, 0, off) - _, err = UnpackStruct(rr, buf, 0) - if err != nil { - return err - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dns_test.go b/Godeps/_workspace/src/github.com/miekg/dns/dns_test.go deleted file mode 100644 index d16fe09f9..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dns_test.go +++ /dev/null @@ -1,581 +0,0 @@ -package dns - -import ( - "encoding/hex" - "net" - "testing" -) - -func TestPackUnpack(t *testing.T) { - out := new(Msg) - out.Answer = make([]RR, 1) - key := new(DNSKEY) - key = &DNSKEY{Flags: 257, Protocol: 3, Algorithm: RSASHA1} - key.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 3600} - key.PublicKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ" - - out.Answer[0] = key - msg, err := out.Pack() - if err != nil { - t.Error("failed to pack msg with DNSKEY") - } - in := new(Msg) - if in.Unpack(msg) != nil { - t.Error("failed to unpack msg with DNSKEY") - } - - sig := new(RRSIG) - sig = &RRSIG{TypeCovered: TypeDNSKEY, Algorithm: RSASHA1, Labels: 2, - OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.", - Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"} - sig.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeRRSIG, Class: ClassINET, Ttl: 3600} - - out.Answer[0] = sig - msg, err = out.Pack() - if err != nil { - t.Error("failed to pack msg with RRSIG") - } - - if in.Unpack(msg) != nil { - t.Error("failed to unpack msg with RRSIG") - } -} - -func TestPackUnpack2(t *testing.T) { - m := new(Msg) - m.Extra = make([]RR, 1) - m.Answer = make([]RR, 1) - dom := "miek.nl." - rr := new(A) - rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0} - rr.A = net.IPv4(127, 0, 0, 1) - - x := new(TXT) - x.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} - x.Txt = []string{"heelalaollo"} - - m.Extra[0] = x - m.Answer[0] = rr - _, err := m.Pack() - if err != nil { - t.Error("Packing failed: ", err) - return - } -} - -func TestPackUnpack3(t *testing.T) { - m := new(Msg) - m.Extra = make([]RR, 2) - m.Answer = make([]RR, 1) - dom := "miek.nl." - rr := new(A) - rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0} - rr.A = net.IPv4(127, 0, 0, 1) - - x1 := new(TXT) - x1.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} - x1.Txt = []string{} - - x2 := new(TXT) - x2.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} - x2.Txt = []string{"heelalaollo"} - - m.Extra[0] = x1 - m.Extra[1] = x2 - m.Answer[0] = rr - b, err := m.Pack() - if err != nil { - t.Error("packing failed: ", err) - return - } - - var unpackMsg Msg - err = unpackMsg.Unpack(b) - if err != nil { - t.Error("unpacking failed") - return - } -} - -func TestBailiwick(t *testing.T) { - yes := map[string]string{ - "miek.nl": "ns.miek.nl", - ".": "miek.nl", - } - for parent, child := range yes { - if !IsSubDomain(parent, child) { - t.Errorf("%s should be child of %s", child, parent) - t.Errorf("comparelabels %d", CompareDomainName(parent, child)) - t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child)) - } - } - no := map[string]string{ - "www.miek.nl": "ns.miek.nl", - "m\\.iek.nl": "ns.miek.nl", - "w\\.iek.nl": "w.iek.nl", - "p\\\\.iek.nl": "ns.p.iek.nl", // p\\.iek.nl , literal \ in domain name - "miek.nl": ".", - } - for parent, child := range no { - if IsSubDomain(parent, child) { - t.Errorf("%s should not be child of %s", child, parent) - t.Errorf("comparelabels %d", CompareDomainName(parent, child)) - t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child)) - } - } -} - -func TestPack(t *testing.T) { - rr := []string{"US. 86400 IN NSEC 0-.us. NS SOA RRSIG NSEC DNSKEY TYPE65534"} - m := new(Msg) - var err error - m.Answer = make([]RR, 1) - for _, r := range rr { - m.Answer[0], err = NewRR(r) - if err != nil { - t.Errorf("failed to create RR: %v", err) - continue - } - if _, err := m.Pack(); err != nil { - t.Errorf("packing failed: %v", err) - } - } - x := new(Msg) - ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org") - ns.(*NS).Ns = "a.ntpns.org" - x.Ns = append(m.Ns, ns) - x.Ns = append(m.Ns, ns) - x.Ns = append(m.Ns, ns) - // This crashes due to the fact the a.ntpns.org isn't a FQDN - // How to recover() from a remove panic()? - if _, err := x.Pack(); err == nil { - t.Error("packing should fail") - } - x.Answer = make([]RR, 1) - x.Answer[0], err = NewRR(rr[0]) - if _, err := x.Pack(); err == nil { - t.Error("packing should fail") - } - x.Question = make([]Question, 1) - x.Question[0] = Question{";sd#edddds鍛↙赏‘℅∥↙xzztsestxssweewwsssstx@s@Z嵌e@cn.pool.ntp.org.", TypeA, ClassINET} - if _, err := x.Pack(); err == nil { - t.Error("packing should fail") - } -} - -func TestPackNAPTR(t *testing.T) { - for _, n := range []string{ - `apple.com. IN NAPTR 100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`, - `apple.com. IN NAPTR 90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`, - `apple.com. IN NAPTR 50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`, - } { - rr, _ := NewRR(n) - msg := make([]byte, rr.len()) - if off, err := PackRR(rr, msg, 0, nil, false); err != nil { - t.Errorf("packing failed: %v", err) - t.Errorf("length %d, need more than %d", rr.len(), off) - } else { - t.Logf("buf size needed: %d", off) - } - } -} - -func TestCompressLength(t *testing.T) { - m := new(Msg) - m.SetQuestion("miek.nl", TypeMX) - ul := m.Len() - m.Compress = true - if ul != m.Len() { - t.Fatalf("should be equal") - } -} - -// Does the predicted length match final packed length? -func TestMsgCompressLength(t *testing.T) { - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - msg.Compress = true - return msg - } - - name1 := "12345678901234567890123456789012345.12345678.123." - rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1") - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - tests := []*Msg{ - makeMsg(name1, []RR{rrA}, nil, nil), - makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)} - - for _, msg := range tests { - predicted := msg.Len() - buf, err := msg.Pack() - if err != nil { - t.Error(err) - } - if predicted < len(buf) { - t.Errorf("predicted compressed length is wrong: predicted %s (len=%d) %d, actual %d", - msg.Question[0].Name, len(msg.Answer), predicted, len(buf)) - } - } -} - -func TestMsgLength(t *testing.T) { - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - return msg - } - - name1 := "12345678901234567890123456789012345.12345678.123." - rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1") - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - tests := []*Msg{ - makeMsg(name1, []RR{rrA}, nil, nil), - makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)} - - for _, msg := range tests { - predicted := msg.Len() - buf, err := msg.Pack() - if err != nil { - t.Error(err) - } - if predicted < len(buf) { - t.Errorf("predicted length is wrong: predicted %s (len=%d), actual %d", - msg.Question[0].Name, predicted, len(buf)) - } - } -} - -func TestMsgLength2(t *testing.T) { - // Serialized replies - var testMessages = []string{ - // google.com. IN A? - "064e81800001000b0004000506676f6f676c6503636f6d0000010001c00c00010001000000050004adc22986c00c00010001000000050004adc22987c00c00010001000000050004adc22988c00c00010001000000050004adc22989c00c00010001000000050004adc2298ec00c00010001000000050004adc22980c00c00010001000000050004adc22981c00c00010001000000050004adc22982c00c00010001000000050004adc22983c00c00010001000000050004adc22984c00c00010001000000050004adc22985c00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc0d800010001000000050004d8ef200ac0ea00010001000000050004d8ef220ac0fc00010001000000050004d8ef240ac10e00010001000000050004d8ef260a0000290500000000050000", - // amazon.com. IN A? (reply has no EDNS0 record) - // TODO(miek): this one is off-by-one, need to find out why - //"6de1818000010004000a000806616d617a6f6e03636f6d0000010001c00c000100010000000500044815c2d4c00c000100010000000500044815d7e8c00c00010001000000050004b02062a6c00c00010001000000050004cdfbf236c00c000200010000000500140570646e733408756c747261646e73036f726700c00c000200010000000500150570646e733508756c747261646e7304696e666f00c00c000200010000000500160570646e733608756c747261646e7302636f02756b00c00c00020001000000050014036e7331037033310664796e656374036e657400c00c00020001000000050006036e7332c0cfc00c00020001000000050006036e7333c0cfc00c00020001000000050006036e7334c0cfc00c000200010000000500110570646e733108756c747261646e73c0dac00c000200010000000500080570646e7332c127c00c000200010000000500080570646e7333c06ec0cb00010001000000050004d04e461fc0eb00010001000000050004cc0dfa1fc0fd00010001000000050004d04e471fc10f00010001000000050004cc0dfb1fc12100010001000000050004cc4a6c01c121001c000100000005001020010502f3ff00000000000000000001c13e00010001000000050004cc4a6d01c13e001c0001000000050010261000a1101400000000000000000001", - // yahoo.com. IN A? - "fc2d81800001000300070008057961686f6f03636f6d0000010001c00c00010001000000050004628afd6dc00c00010001000000050004628bb718c00c00010001000000050004cebe242dc00c00020001000000050006036e7336c00cc00c00020001000000050006036e7338c00cc00c00020001000000050006036e7331c00cc00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7335c00cc07b0001000100000005000444b48310c08d00010001000000050004448eff10c09f00010001000000050004cb54dd35c0b100010001000000050004628a0b9dc0c30001000100000005000477a0f77cc05700010001000000050004ca2bdfaac06900010001000000050004caa568160000290500000000050000", - // microsoft.com. IN A? - "f4368180000100020005000b096d6963726f736f667403636f6d0000010001c00c0001000100000005000440040b25c00c0001000100000005000441373ac9c00c0002000100000005000e036e7331046d736674036e657400c00c00020001000000050006036e7332c04fc00c00020001000000050006036e7333c04fc00c00020001000000050006036e7334c04fc00c00020001000000050006036e7335c04fc04b000100010000000500044137253ec04b001c00010000000500102a010111200500000000000000010001c0650001000100000005000440043badc065001c00010000000500102a010111200600060000000000010001c07700010001000000050004d5c7b435c077001c00010000000500102a010111202000000000000000010001c08900010001000000050004cf2e4bfec089001c00010000000500102404f800200300000000000000010001c09b000100010000000500044137e28cc09b001c00010000000500102a010111200f000100000000000100010000290500000000050000", - // google.com. IN MX? - "724b8180000100050004000b06676f6f676c6503636f6d00000f0001c00c000f000100000005000c000a056173706d78016cc00cc00c000f0001000000050009001404616c7431c02ac00c000f0001000000050009001e04616c7432c02ac00c000f0001000000050009002804616c7433c02ac00c000f0001000000050009003204616c7434c02ac00c00020001000000050006036e7332c00cc00c00020001000000050006036e7333c00cc00c00020001000000050006036e7334c00cc00c00020001000000050006036e7331c00cc02a00010001000000050004adc2421bc02a001c00010000000500102a00145040080c01000000000000001bc04200010001000000050004adc2461bc05700010001000000050004adc2451bc06c000100010000000500044a7d8f1bc081000100010000000500044a7d191bc0ca00010001000000050004d8ef200ac09400010001000000050004d8ef220ac0a600010001000000050004d8ef240ac0b800010001000000050004d8ef260a0000290500000000050000", - // reddit.com. IN A? - "12b98180000100080000000c0672656464697403636f6d0000020001c00c0002000100000005000f046175733204616b616d036e657400c00c000200010000000500070475736534c02dc00c000200010000000500070475737733c02dc00c000200010000000500070475737735c02dc00c00020001000000050008056173696131c02dc00c00020001000000050008056173696139c02dc00c00020001000000050008056e73312d31c02dc00c0002000100000005000a076e73312d313935c02dc02800010001000000050004c30a242ec04300010001000000050004451f1d39c05600010001000000050004451f3bc7c0690001000100000005000460073240c07c000100010000000500046007fb81c090000100010000000500047c283484c090001c00010000000500102a0226f0006700000000000000000064c0a400010001000000050004c16c5b01c0a4001c000100000005001026001401000200000000000000000001c0b800010001000000050004c16c5bc3c0b8001c0001000000050010260014010002000000000000000000c30000290500000000050000", - } - - for i, hexData := range testMessages { - // we won't fail the decoding of the hex - input, _ := hex.DecodeString(hexData) - m := new(Msg) - m.Unpack(input) - //println(m.String()) - m.Compress = true - lenComp := m.Len() - b, _ := m.Pack() - pacComp := len(b) - m.Compress = false - lenUnComp := m.Len() - b, _ = m.Pack() - pacUnComp := len(b) - if pacComp+1 != lenComp { - t.Errorf("msg.Len(compressed)=%d actual=%d for test %d", lenComp, pacComp, i) - } - if pacUnComp+1 != lenUnComp { - t.Errorf("msg.Len(uncompressed)=%d actual=%d for test %d", lenUnComp, pacUnComp, i) - } - } -} - -func TestMsgLengthCompressionMalformed(t *testing.T) { - // SOA with empty hostmaster, which is illegal - soa := &SOA{Hdr: RR_Header{Name: ".", Rrtype: TypeSOA, Class: ClassINET, Ttl: 12345}, - Ns: ".", - Mbox: "", - Serial: 0, - Refresh: 28800, - Retry: 7200, - Expire: 604800, - Minttl: 60} - m := new(Msg) - m.Compress = true - m.Ns = []RR{soa} - m.Len() // Should not crash. -} - -func BenchmarkMsgLength(b *testing.B) { - b.StopTimer() - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - msg.Compress = true - return msg - } - name1 := "12345678901234567890123456789012345.12345678.123." - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil) - b.StartTimer() - for i := 0; i < b.N; i++ { - msg.Len() - } -} - -func BenchmarkMsgLengthPack(b *testing.B) { - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - msg.Compress = true - return msg - } - name1 := "12345678901234567890123456789012345.12345678.123." - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = msg.Pack() - } -} - -func BenchmarkMsgPackBuffer(b *testing.B) { - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - msg.Compress = true - return msg - } - name1 := "12345678901234567890123456789012345.12345678.123." - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil) - buf := make([]byte, 512) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = msg.PackBuffer(buf) - } -} - -func BenchmarkMsgUnpack(b *testing.B) { - makeMsg := func(question string, ans, ns, e []RR) *Msg { - msg := new(Msg) - msg.SetQuestion(Fqdn(question), TypeANY) - msg.Answer = append(msg.Answer, ans...) - msg.Ns = append(msg.Ns, ns...) - msg.Extra = append(msg.Extra, e...) - msg.Compress = true - return msg - } - name1 := "12345678901234567890123456789012345.12345678.123." - rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1) - msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil) - msgBuf, _ := msg.Pack() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = msg.Unpack(msgBuf) - } -} - -func BenchmarkPackDomainName(b *testing.B) { - name1 := "12345678901234567890123456789012345.12345678.123." - buf := make([]byte, len(name1)+1) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = PackDomainName(name1, buf, 0, nil, false) - } -} - -func BenchmarkUnpackDomainName(b *testing.B) { - name1 := "12345678901234567890123456789012345.12345678.123." - buf := make([]byte, len(name1)+1) - _, _ = PackDomainName(name1, buf, 0, nil, false) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _, _ = UnpackDomainName(buf, 0) - } -} - -func BenchmarkUnpackDomainNameUnprintable(b *testing.B) { - name1 := "\x02\x02\x02\x025\x02\x02\x02\x02.12345678.123." - buf := make([]byte, len(name1)+1) - _, _ = PackDomainName(name1, buf, 0, nil, false) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _, _ = UnpackDomainName(buf, 0) - } -} - -func TestToRFC3597(t *testing.T) { - a, _ := NewRR("miek.nl. IN A 10.0.1.1") - x := new(RFC3597) - x.ToRFC3597(a) - if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` { - t.Error("string mismatch") - } -} - -func TestNoRdataPack(t *testing.T) { - data := make([]byte, 1024) - for typ, fn := range typeToRR { - if typ == TypeCAA { - continue // TODO(miek): known omission - } - r := fn() - *r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600} - _, err := PackRR(r, data, 0, nil, false) - if err != nil { - t.Errorf("failed to pack RR with zero rdata: %s: %v", TypeToString[typ], err) - } - } -} - -// TODO(miek): fix dns buffer too small errors this throws -func TestNoRdataUnpack(t *testing.T) { - data := make([]byte, 1024) - for typ, fn := range typeToRR { - if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS { - // SOA, TSIG will not be seen (like this) in dyn. updates? - // WKS is an bug, but...deprecated record. - continue - } - r := fn() - *r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600} - off, err := PackRR(r, data, 0, nil, false) - if err != nil { - // Should always works, TestNoDataPack should have caught this - t.Errorf("failed to pack RR: %v", err) - continue - } - rr, _, err := UnpackRR(data[:off], 0) - if err != nil { - t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err) - } - t.Log(rr) - } -} - -func TestRdataOverflow(t *testing.T) { - rr := new(RFC3597) - rr.Hdr.Name = "." - rr.Hdr.Class = ClassINET - rr.Hdr.Rrtype = 65280 - rr.Rdata = hex.EncodeToString(make([]byte, 0xFFFF)) - buf := make([]byte, 0xFFFF*2) - if _, err := PackRR(rr, buf, 0, nil, false); err != nil { - t.Fatalf("maximum size rrdata pack failed: %v", err) - } - rr.Rdata += "00" - if _, err := PackRR(rr, buf, 0, nil, false); err != ErrRdata { - t.Fatalf("oversize rrdata pack didn't return ErrRdata - instead: %v", err) - } -} - -func TestCopy(t *testing.T) { - rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL - rr1 := Copy(rr) - if rr.String() != rr1.String() { - t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String()) - } -} - -func TestMsgCopy(t *testing.T) { - m := new(Msg) - m.SetQuestion("miek.nl.", TypeA) - rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") - m.Answer = []RR{rr} - rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1") - m.Ns = []RR{rr} - - m1 := m.Copy() - if m.String() != m1.String() { - t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String()) - } - - m1.Answer[0], _ = NewRR("somethingelse.nl. 2311 IN A 127.0.0.1") - if m.String() == m1.String() { - t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String()) - } - - rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.2") - m1.Answer = append(m1.Answer, rr) - if m1.Ns[0].String() == m1.Answer[1].String() { - t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String()) - } -} - -func BenchmarkCopy(b *testing.B) { - b.ReportAllocs() - m := new(Msg) - m.SetQuestion("miek.nl.", TypeA) - rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") - m.Answer = []RR{rr} - rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1") - m.Ns = []RR{rr} - rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.1") - m.Extra = []RR{rr} - - b.ResetTimer() - for i := 0; i < b.N; i++ { - m.Copy() - } -} - -func TestPackIPSECKEY(t *testing.T) { - tests := []string{ - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - } - buf := make([]byte, 1024) - for _, t1 := range tests { - rr, _ := NewRR(t1) - off, err := PackRR(rr, buf, 0, nil, false) - if err != nil { - t.Errorf("failed to pack IPSECKEY %v: %s", err, t1) - continue - } - - rr, _, err = UnpackRR(buf[:off], 0) - if err != nil { - t.Errorf("failed to unpack IPSECKEY %v: %s", err, t1) - } - t.Log(rr) - } -} - -func TestMsgPackBuffer(t *testing.T) { - var testMessages = []string{ - // news.ycombinator.com.in.escapemg.com. IN A, response - "586285830001000000010000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001c0210006000100000e10002c036e7332c02103646e730b67726f6f7665736861726bc02d77ed50e600002a3000000e1000093a8000000e10", - - // news.ycombinator.com.in.escapemg.com. IN A, question - "586201000001000000000000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001", - - "398781020001000000000000046e6577730b79636f6d62696e61746f7203636f6d0000010001", - } - - for i, hexData := range testMessages { - // we won't fail the decoding of the hex - input, _ := hex.DecodeString(hexData) - m := new(Msg) - if err := m.Unpack(input); err != nil { - t.Errorf("packet %d failed to unpack", i) - continue - } - t.Logf("packet %d %s", i, m.String()) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go deleted file mode 100644 index 21ef3775a..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go +++ /dev/null @@ -1,634 +0,0 @@ -package dns - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/md5" - "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "hash" - "io" - "math/big" - "sort" - "strings" - "time" -) - -// DNSSEC encryption algorithm codes. -const ( - _ uint8 = iota - RSAMD5 - DH - DSA - _ // Skip 4, RFC 6725, section 2.1 - RSASHA1 - DSANSEC3SHA1 - RSASHA1NSEC3SHA1 - RSASHA256 - _ // Skip 9, RFC 6725, section 2.1 - RSASHA512 - _ // Skip 11, RFC 6725, section 2.1 - ECCGOST - ECDSAP256SHA256 - ECDSAP384SHA384 - INDIRECT uint8 = 252 - PRIVATEDNS uint8 = 253 // Private (experimental keys) - PRIVATEOID uint8 = 254 -) - -// DNSSEC hashing algorithm codes. -const ( - _ uint8 = iota - SHA1 // RFC 4034 - SHA256 // RFC 4509 - GOST94 // RFC 5933 - SHA384 // Experimental - SHA512 // Experimental -) - -// DNSKEY flag values. -const ( - SEP = 1 - REVOKE = 1 << 7 - ZONE = 1 << 8 -) - -// The RRSIG needs to be converted to wireformat with some of -// the rdata (the signature) missing. Use this struct to easy -// the conversion (and re-use the pack/unpack functions). -type rrsigWireFmt struct { - TypeCovered uint16 - Algorithm uint8 - Labels uint8 - OrigTtl uint32 - Expiration uint32 - Inception uint32 - KeyTag uint16 - SignerName string `dns:"domain-name"` - /* No Signature */ -} - -// Used for converting DNSKEY's rdata to wirefmt. -type dnskeyWireFmt struct { - Flags uint16 - Protocol uint8 - Algorithm uint8 - PublicKey string `dns:"base64"` - /* Nothing is left out */ -} - -func divRoundUp(a, b int) int { - return (a + b - 1) / b -} - -// KeyTag calculates the keytag (or key-id) of the DNSKEY. -func (k *DNSKEY) KeyTag() uint16 { - if k == nil { - return 0 - } - var keytag int - switch k.Algorithm { - case RSAMD5: - // Look at the bottom two bytes of the modules, which the last - // item in the pubkey. We could do this faster by looking directly - // at the base64 values. But I'm lazy. - modulus, _ := fromBase64([]byte(k.PublicKey)) - if len(modulus) > 1 { - x, _ := unpackUint16(modulus, len(modulus)-2) - keytag = int(x) - } - default: - keywire := new(dnskeyWireFmt) - keywire.Flags = k.Flags - keywire.Protocol = k.Protocol - keywire.Algorithm = k.Algorithm - keywire.PublicKey = k.PublicKey - wire := make([]byte, DefaultMsgSize) - n, err := PackStruct(keywire, wire, 0) - if err != nil { - return 0 - } - wire = wire[:n] - for i, v := range wire { - if i&1 != 0 { - keytag += int(v) // must be larger than uint32 - } else { - keytag += int(v) << 8 - } - } - keytag += (keytag >> 16) & 0xFFFF - keytag &= 0xFFFF - } - return uint16(keytag) -} - -// ToDS converts a DNSKEY record to a DS record. -func (k *DNSKEY) ToDS(h uint8) *DS { - if k == nil { - return nil - } - ds := new(DS) - ds.Hdr.Name = k.Hdr.Name - ds.Hdr.Class = k.Hdr.Class - ds.Hdr.Rrtype = TypeDS - ds.Hdr.Ttl = k.Hdr.Ttl - ds.Algorithm = k.Algorithm - ds.DigestType = h - ds.KeyTag = k.KeyTag() - - keywire := new(dnskeyWireFmt) - keywire.Flags = k.Flags - keywire.Protocol = k.Protocol - keywire.Algorithm = k.Algorithm - keywire.PublicKey = k.PublicKey - wire := make([]byte, DefaultMsgSize) - n, err := PackStruct(keywire, wire, 0) - if err != nil { - return nil - } - wire = wire[:n] - - owner := make([]byte, 255) - off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false) - if err1 != nil { - return nil - } - owner = owner[:off] - // RFC4034: - // digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); - // "|" denotes concatenation - // DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. - - // digest buffer - digest := append(owner, wire...) // another copy - - switch h { - case SHA1: - s := sha1.New() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) - case SHA256: - s := sha256.New() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) - case SHA384: - s := sha512.New384() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) - case GOST94: - /* I have no clue */ - default: - return nil - } - return ds -} - -// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record. -func (k *DNSKEY) ToCDNSKEY() *CDNSKEY { - c := &CDNSKEY{DNSKEY: *k} - c.Hdr = *k.Hdr.copyHeader() - c.Hdr.Rrtype = TypeCDNSKEY - return c -} - -// ToCDS converts a DS record to a CDS record. -func (d *DS) ToCDS() *CDS { - c := &CDS{DS: *d} - c.Hdr = *d.Hdr.copyHeader() - c.Hdr.Rrtype = TypeCDS - return c -} - -// Sign signs an RRSet. The signature needs to be filled in with -// the values: Inception, Expiration, KeyTag, SignerName and Algorithm. -// The rest is copied from the RRset. Sign returns true when the signing went OK, -// otherwise false. -// There is no check if RRSet is a proper (RFC 2181) RRSet. -// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset -// is used as the OrigTTL. -func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { - if k == nil { - return ErrPrivKey - } - // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set - if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { - return ErrKey - } - - rr.Hdr.Rrtype = TypeRRSIG - rr.Hdr.Name = rrset[0].Header().Name - rr.Hdr.Class = rrset[0].Header().Class - if rr.OrigTtl == 0 { // If set don't override - rr.OrigTtl = rrset[0].Header().Ttl - } - rr.TypeCovered = rrset[0].Header().Rrtype - rr.Labels = uint8(CountLabel(rrset[0].Header().Name)) - - if strings.HasPrefix(rrset[0].Header().Name, "*") { - rr.Labels-- // wildcard, remove from label count - } - - sigwire := new(rrsigWireFmt) - sigwire.TypeCovered = rr.TypeCovered - sigwire.Algorithm = rr.Algorithm - sigwire.Labels = rr.Labels - sigwire.OrigTtl = rr.OrigTtl - sigwire.Expiration = rr.Expiration - sigwire.Inception = rr.Inception - sigwire.KeyTag = rr.KeyTag - // For signing, lowercase this name - sigwire.SignerName = strings.ToLower(rr.SignerName) - - // Create the desired binary blob - signdata := make([]byte, DefaultMsgSize) - n, err := PackStruct(sigwire, signdata, 0) - if err != nil { - return err - } - signdata = signdata[:n] - wire, err := rawSignatureData(rrset, rr) - if err != nil { - return err - } - signdata = append(signdata, wire...) - - var h hash.Hash - switch rr.Algorithm { - case DSA, DSANSEC3SHA1: - // TODO: this seems bugged, will panic - case RSASHA1, RSASHA1NSEC3SHA1: - h = sha1.New() - case RSASHA256, ECDSAP256SHA256: - h = sha256.New() - case ECDSAP384SHA384: - h = sha512.New384() - case RSASHA512: - h = sha512.New() - case RSAMD5: - fallthrough // Deprecated in RFC 6725 - default: - return ErrAlg - } - - _, err = h.Write(signdata) - if err != nil { - return err - } - sighash := h.Sum(nil) - - signature, err := k.Sign(sighash, rr.Algorithm) - if err != nil { - return err - } - rr.Signature = toBase64(signature) - - return nil -} - -// Verify validates an RRSet with the signature and key. This is only the -// cryptographic test, the signature validity period must be checked separately. -// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work. -func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { - // First the easy checks - if len(rrset) == 0 { - return ErrRRset - } - if rr.KeyTag != k.KeyTag() { - return ErrKey - } - if rr.Hdr.Class != k.Hdr.Class { - return ErrKey - } - if rr.Algorithm != k.Algorithm { - return ErrKey - } - if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) { - return ErrKey - } - if k.Protocol != 3 { - return ErrKey - } - for _, r := range rrset { - if r.Header().Class != rr.Hdr.Class { - return ErrRRset - } - if r.Header().Rrtype != rr.TypeCovered { - return ErrRRset - } - } - // RFC 4035 5.3.2. Reconstructing the Signed Data - // Copy the sig, except the rrsig data - sigwire := new(rrsigWireFmt) - sigwire.TypeCovered = rr.TypeCovered - sigwire.Algorithm = rr.Algorithm - sigwire.Labels = rr.Labels - sigwire.OrigTtl = rr.OrigTtl - sigwire.Expiration = rr.Expiration - sigwire.Inception = rr.Inception - sigwire.KeyTag = rr.KeyTag - sigwire.SignerName = strings.ToLower(rr.SignerName) - // Create the desired binary blob - signeddata := make([]byte, DefaultMsgSize) - n, err := PackStruct(sigwire, signeddata, 0) - if err != nil { - return err - } - signeddata = signeddata[:n] - wire, err := rawSignatureData(rrset, rr) - if err != nil { - return err - } - signeddata = append(signeddata, wire...) - - sigbuf := rr.sigBuf() // Get the binary signature data - if rr.Algorithm == PRIVATEDNS { // PRIVATEOID - // TODO(mg) - // remove the domain name and assume its our - } - - switch rr.Algorithm { - case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5: - // TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere?? - pubkey := k.publicKeyRSA() // Get the key - if pubkey == nil { - return ErrKey - } - // Setup the hash as defined for this alg. - var h hash.Hash - var ch crypto.Hash - switch rr.Algorithm { - case RSAMD5: - h = md5.New() - ch = crypto.MD5 - case RSASHA1, RSASHA1NSEC3SHA1: - h = sha1.New() - ch = crypto.SHA1 - case RSASHA256: - h = sha256.New() - ch = crypto.SHA256 - case RSASHA512: - h = sha512.New() - ch = crypto.SHA512 - } - io.WriteString(h, string(signeddata)) - sighash := h.Sum(nil) - return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf) - case ECDSAP256SHA256, ECDSAP384SHA384: - pubkey := k.publicKeyECDSA() - if pubkey == nil { - return ErrKey - } - var h hash.Hash - switch rr.Algorithm { - case ECDSAP256SHA256: - h = sha256.New() - case ECDSAP384SHA384: - h = sha512.New384() - } - io.WriteString(h, string(signeddata)) - sighash := h.Sum(nil) - // Split sigbuf into the r and s coordinates - r := big.NewInt(0) - r.SetBytes(sigbuf[:len(sigbuf)/2]) - s := big.NewInt(0) - s.SetBytes(sigbuf[len(sigbuf)/2:]) - if ecdsa.Verify(pubkey, sighash, r, s) { - return nil - } - return ErrSig - } - // Unknown alg - return ErrAlg -} - -// ValidityPeriod uses RFC1982 serial arithmetic to calculate -// if a signature period is valid. If t is the zero time, the -// current time is taken other t is. -func (rr *RRSIG) ValidityPeriod(t time.Time) bool { - var utc int64 - if t.IsZero() { - utc = time.Now().UTC().Unix() - } else { - utc = t.UTC().Unix() - } - modi := (int64(rr.Inception) - utc) / year68 - mode := (int64(rr.Expiration) - utc) / year68 - ti := int64(rr.Inception) + (modi * year68) - te := int64(rr.Expiration) + (mode * year68) - return ti <= utc && utc <= te -} - -// Return the signatures base64 encodedig sigdata as a byte slice. -func (rr *RRSIG) sigBuf() []byte { - sigbuf, err := fromBase64([]byte(rr.Signature)) - if err != nil { - return nil - } - return sigbuf -} - -// publicKeyRSA returns the RSA public key from a DNSKEY record. -func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey { - keybuf, err := fromBase64([]byte(k.PublicKey)) - if err != nil { - return nil - } - - // RFC 2537/3110, section 2. RSA Public KEY Resource Records - // Length is in the 0th byte, unless its zero, then it - // it in bytes 1 and 2 and its a 16 bit number - explen := uint16(keybuf[0]) - keyoff := 1 - if explen == 0 { - explen = uint16(keybuf[1])<<8 | uint16(keybuf[2]) - keyoff = 3 - } - pubkey := new(rsa.PublicKey) - - pubkey.N = big.NewInt(0) - shift := uint64((explen - 1) * 8) - expo := uint64(0) - for i := int(explen - 1); i > 0; i-- { - expo += uint64(keybuf[keyoff+i]) << shift - shift -= 8 - } - // Remainder - expo += uint64(keybuf[keyoff]) - if expo > 2<<31 { - // Larger expo than supported. - // println("dns: F5 primes (or larger) are not supported") - return nil - } - pubkey.E = int(expo) - - pubkey.N.SetBytes(keybuf[keyoff+int(explen):]) - return pubkey -} - -// publicKeyECDSA returns the Curve public key from the DNSKEY record. -func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey { - keybuf, err := fromBase64([]byte(k.PublicKey)) - if err != nil { - return nil - } - pubkey := new(ecdsa.PublicKey) - switch k.Algorithm { - case ECDSAP256SHA256: - pubkey.Curve = elliptic.P256() - if len(keybuf) != 64 { - // wrongly encoded key - return nil - } - case ECDSAP384SHA384: - pubkey.Curve = elliptic.P384() - if len(keybuf) != 96 { - // Wrongly encoded key - return nil - } - } - pubkey.X = big.NewInt(0) - pubkey.X.SetBytes(keybuf[:len(keybuf)/2]) - pubkey.Y = big.NewInt(0) - pubkey.Y.SetBytes(keybuf[len(keybuf)/2:]) - return pubkey -} - -func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey { - keybuf, err := fromBase64([]byte(k.PublicKey)) - if err != nil { - return nil - } - if len(keybuf) < 22 { - return nil - } - t, keybuf := int(keybuf[0]), keybuf[1:] - size := 64 + t*8 - q, keybuf := keybuf[:20], keybuf[20:] - if len(keybuf) != 3*size { - return nil - } - p, keybuf := keybuf[:size], keybuf[size:] - g, y := keybuf[:size], keybuf[size:] - pubkey := new(dsa.PublicKey) - pubkey.Parameters.Q = big.NewInt(0).SetBytes(q) - pubkey.Parameters.P = big.NewInt(0).SetBytes(p) - pubkey.Parameters.G = big.NewInt(0).SetBytes(g) - pubkey.Y = big.NewInt(0).SetBytes(y) - return pubkey -} - -type wireSlice [][]byte - -func (p wireSlice) Len() int { return len(p) } -func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p wireSlice) Less(i, j int) bool { - _, ioff, _ := UnpackDomainName(p[i], 0) - _, joff, _ := UnpackDomainName(p[j], 0) - return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0 -} - -// Return the raw signature data. -func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { - wires := make(wireSlice, len(rrset)) - for i, r := range rrset { - r1 := r.copy() - r1.Header().Ttl = s.OrigTtl - labels := SplitDomainName(r1.Header().Name) - // 6.2. Canonical RR Form. (4) - wildcards - if len(labels) > int(s.Labels) { - // Wildcard - r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "." - } - // RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase - r1.Header().Name = strings.ToLower(r1.Header().Name) - // 6.2. Canonical RR Form. (3) - domain rdata to lowercase. - // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR, - // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, - // SRV, DNAME, A6 - switch x := r1.(type) { - case *NS: - x.Ns = strings.ToLower(x.Ns) - case *CNAME: - x.Target = strings.ToLower(x.Target) - case *SOA: - x.Ns = strings.ToLower(x.Ns) - x.Mbox = strings.ToLower(x.Mbox) - case *MB: - x.Mb = strings.ToLower(x.Mb) - case *MG: - x.Mg = strings.ToLower(x.Mg) - case *MR: - x.Mr = strings.ToLower(x.Mr) - case *PTR: - x.Ptr = strings.ToLower(x.Ptr) - case *MINFO: - x.Rmail = strings.ToLower(x.Rmail) - x.Email = strings.ToLower(x.Email) - case *MX: - x.Mx = strings.ToLower(x.Mx) - case *NAPTR: - x.Replacement = strings.ToLower(x.Replacement) - case *KX: - x.Exchanger = strings.ToLower(x.Exchanger) - case *SRV: - x.Target = strings.ToLower(x.Target) - case *DNAME: - x.Target = strings.ToLower(x.Target) - } - // 6.2. Canonical RR Form. (5) - origTTL - wire := make([]byte, r1.len()+1) // +1 to be safe(r) - off, err1 := PackRR(r1, wire, 0, nil, false) - if err1 != nil { - return nil, err1 - } - wire = wire[:off] - wires[i] = wire - } - sort.Sort(wires) - for i, wire := range wires { - if i > 0 && bytes.Equal(wire, wires[i-1]) { - continue - } - buf = append(buf, wire...) - } - return buf, nil -} - -// Map for algorithm names. -var AlgorithmToString = map[uint8]string{ - RSAMD5: "RSAMD5", - DH: "DH", - DSA: "DSA", - RSASHA1: "RSASHA1", - DSANSEC3SHA1: "DSA-NSEC3-SHA1", - RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1", - RSASHA256: "RSASHA256", - RSASHA512: "RSASHA512", - ECCGOST: "ECC-GOST", - ECDSAP256SHA256: "ECDSAP256SHA256", - ECDSAP384SHA384: "ECDSAP384SHA384", - INDIRECT: "INDIRECT", - PRIVATEDNS: "PRIVATEDNS", - PRIVATEOID: "PRIVATEOID", -} - -// Map of algorithm strings. -var StringToAlgorithm = reverseInt8(AlgorithmToString) - -// Map for hash names. -var HashToString = map[uint8]string{ - SHA1: "SHA1", - SHA256: "SHA256", - GOST94: "GOST94", - SHA384: "SHA384", - SHA512: "SHA512", -} - -// Map of hash strings. -var StringToHash = reverseInt8(HashToString) diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go deleted file mode 100644 index 739beebe0..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go +++ /dev/null @@ -1,155 +0,0 @@ -package dns - -import ( - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "math/big" -) - -// Generate generates a DNSKEY of the given bit size. -// The public part is put inside the DNSKEY record. -// The Algorithm in the key must be set as this will define -// what kind of DNSKEY will be generated. -// The ECDSA algorithms imply a fixed keysize, in that case -// bits should be set to the size of the algorithm. -func (k *DNSKEY) Generate(bits int) (PrivateKey, error) { - switch k.Algorithm { - case DSA, DSANSEC3SHA1: - if bits != 1024 { - return nil, ErrKeySize - } - case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1: - if bits < 512 || bits > 4096 { - return nil, ErrKeySize - } - case RSASHA512: - if bits < 1024 || bits > 4096 { - return nil, ErrKeySize - } - case ECDSAP256SHA256: - if bits != 256 { - return nil, ErrKeySize - } - case ECDSAP384SHA384: - if bits != 384 { - return nil, ErrKeySize - } - } - - switch k.Algorithm { - case DSA, DSANSEC3SHA1: - params := new(dsa.Parameters) - if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil { - return nil, err - } - priv := new(dsa.PrivateKey) - priv.PublicKey.Parameters = *params - err := dsa.GenerateKey(priv, rand.Reader) - if err != nil { - return nil, err - } - k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y) - return (*DSAPrivateKey)(priv), nil - case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1: - priv, err := rsa.GenerateKey(rand.Reader, bits) - if err != nil { - return nil, err - } - k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N) - return (*RSAPrivateKey)(priv), nil - case ECDSAP256SHA256, ECDSAP384SHA384: - var c elliptic.Curve - switch k.Algorithm { - case ECDSAP256SHA256: - c = elliptic.P256() - case ECDSAP384SHA384: - c = elliptic.P384() - } - priv, err := ecdsa.GenerateKey(c, rand.Reader) - if err != nil { - return nil, err - } - k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y) - return (*ECDSAPrivateKey)(priv), nil - default: - return nil, ErrAlg - } -} - -// Set the public key (the value E and N) -func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool { - if _E == 0 || _N == nil { - return false - } - buf := exponentToBuf(_E) - buf = append(buf, _N.Bytes()...) - k.PublicKey = toBase64(buf) - return true -} - -// Set the public key for Elliptic Curves -func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool { - if _X == nil || _Y == nil { - return false - } - var intlen int - switch k.Algorithm { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - } - k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen)) - return true -} - -// Set the public key for DSA -func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool { - if _Q == nil || _P == nil || _G == nil || _Y == nil { - return false - } - buf := dsaToBuf(_Q, _P, _G, _Y) - k.PublicKey = toBase64(buf) - return true -} - -// Set the public key (the values E and N) for RSA -// RFC 3110: Section 2. RSA Public KEY Resource Records -func exponentToBuf(_E int) []byte { - var buf []byte - i := big.NewInt(int64(_E)) - if len(i.Bytes()) < 256 { - buf = make([]byte, 1) - buf[0] = uint8(len(i.Bytes())) - } else { - buf = make([]byte, 3) - buf[0] = 0 - buf[1] = uint8(len(i.Bytes()) >> 8) - buf[2] = uint8(len(i.Bytes())) - } - buf = append(buf, i.Bytes()...) - return buf -} - -// Set the public key for X and Y for Curve. The two -// values are just concatenated. -func curveToBuf(_X, _Y *big.Int, intlen int) []byte { - buf := intToBytes(_X, intlen) - buf = append(buf, intToBytes(_Y, intlen)...) - return buf -} - -// Set the public key for X and Y for Curve. The two -// values are just concatenated. -func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte { - t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8) - buf := []byte{byte(t)} - buf = append(buf, intToBytes(_Q, 20)...) - buf = append(buf, intToBytes(_P, 64+t*8)...) - buf = append(buf, intToBytes(_G, 64+t*8)...) - buf = append(buf, intToBytes(_Y, 64+t*8)...) - return buf -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go deleted file mode 100644 index d9c0d9b5c..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go +++ /dev/null @@ -1,243 +0,0 @@ -package dns - -import ( - "crypto/dsa" - "crypto/ecdsa" - "crypto/rsa" - "io" - "math/big" - "strings" -) - -// NewPrivateKey returns a PrivateKey by parsing the string s. -// s should be in the same form of the BIND private key files. -func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { - if s[len(s)-1] != '\n' { // We need a closing newline - return k.ReadPrivateKey(strings.NewReader(s+"\n"), "") - } - return k.ReadPrivateKey(strings.NewReader(s), "") -} - -// ReadPrivateKey reads a private key from the io.Reader q. The string file is -// only used in error reporting. -// The public key must be known, because some cryptographic algorithms embed -// the public inside the privatekey. -func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { - m, e := parseKey(q, file) - if m == nil { - return nil, e - } - if _, ok := m["private-key-format"]; !ok { - return nil, ErrPrivKey - } - if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" { - return nil, ErrPrivKey - } - // TODO(mg): check if the pubkey matches the private key - switch m["algorithm"] { - case "3 (DSA)": - priv, e := readPrivateKeyDSA(m) - if e != nil { - return nil, e - } - pub := k.publicKeyDSA() - if pub == nil { - return nil, ErrKey - } - priv.PublicKey = *pub - return (*DSAPrivateKey)(priv), e - case "1 (RSAMD5)": - fallthrough - case "5 (RSASHA1)": - fallthrough - case "7 (RSASHA1NSEC3SHA1)": - fallthrough - case "8 (RSASHA256)": - fallthrough - case "10 (RSASHA512)": - priv, e := readPrivateKeyRSA(m) - if e != nil { - return nil, e - } - pub := k.publicKeyRSA() - if pub == nil { - return nil, ErrKey - } - priv.PublicKey = *pub - return (*RSAPrivateKey)(priv), e - case "12 (ECC-GOST)": - return nil, ErrPrivKey - case "13 (ECDSAP256SHA256)": - fallthrough - case "14 (ECDSAP384SHA384)": - priv, e := readPrivateKeyECDSA(m) - if e != nil { - return nil, e - } - pub := k.publicKeyECDSA() - if pub == nil { - return nil, ErrKey - } - priv.PublicKey = *pub - return (*ECDSAPrivateKey)(priv), e - default: - return nil, ErrPrivKey - } -} - -// Read a private key (file) string and create a public key. Return the private key. -func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) { - p := new(rsa.PrivateKey) - p.Primes = []*big.Int{nil, nil} - for k, v := range m { - switch k { - case "modulus", "publicexponent", "privateexponent", "prime1", "prime2": - v1, err := fromBase64([]byte(v)) - if err != nil { - return nil, err - } - switch k { - case "modulus": - p.PublicKey.N = big.NewInt(0) - p.PublicKey.N.SetBytes(v1) - case "publicexponent": - i := big.NewInt(0) - i.SetBytes(v1) - p.PublicKey.E = int(i.Int64()) // int64 should be large enough - case "privateexponent": - p.D = big.NewInt(0) - p.D.SetBytes(v1) - case "prime1": - p.Primes[0] = big.NewInt(0) - p.Primes[0].SetBytes(v1) - case "prime2": - p.Primes[1] = big.NewInt(0) - p.Primes[1].SetBytes(v1) - } - case "exponent1", "exponent2", "coefficient": - // not used in Go (yet) - case "created", "publish", "activate": - // not used in Go (yet) - } - } - return p, nil -} - -func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) { - p := new(dsa.PrivateKey) - p.X = big.NewInt(0) - for k, v := range m { - switch k { - case "private_value(x)": - v1, err := fromBase64([]byte(v)) - if err != nil { - return nil, err - } - p.X.SetBytes(v1) - case "created", "publish", "activate": - /* not used in Go (yet) */ - } - } - return p, nil -} - -func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) { - p := new(ecdsa.PrivateKey) - p.D = big.NewInt(0) - // TODO: validate that the required flags are present - for k, v := range m { - switch k { - case "privatekey": - v1, err := fromBase64([]byte(v)) - if err != nil { - return nil, err - } - p.D.SetBytes(v1) - case "created", "publish", "activate": - /* not used in Go (yet) */ - } - } - return p, nil -} - -// parseKey reads a private key from r. It returns a map[string]string, -// with the key-value pairs, or an error when the file is not correct. -func parseKey(r io.Reader, file string) (map[string]string, error) { - s := scanInit(r) - m := make(map[string]string) - c := make(chan lex) - k := "" - // Start the lexer - go klexer(s, c) - for l := range c { - // It should alternate - switch l.value { - case zKey: - k = l.token - case zValue: - if k == "" { - return nil, &ParseError{file, "no private key seen", l} - } - //println("Setting", strings.ToLower(k), "to", l.token, "b") - m[strings.ToLower(k)] = l.token - k = "" - } - } - return m, nil -} - -// klexer scans the sourcefile and returns tokens on the channel c. -func klexer(s *scan, c chan lex) { - var l lex - str := "" // Hold the current read text - commt := false - key := true - x, err := s.tokenText() - defer close(c) - for err == nil { - l.column = s.position.Column - l.line = s.position.Line - switch x { - case ':': - if commt { - break - } - l.token = str - if key { - l.value = zKey - c <- l - // Next token is a space, eat it - s.tokenText() - key = false - str = "" - } else { - l.value = zValue - } - case ';': - commt = true - case '\n': - if commt { - // Reset a comment - commt = false - } - l.value = zValue - l.token = str - c <- l - str = "" - commt = false - key = true - default: - if commt { - break - } - str += string(x) - } - x, err = s.tokenText() - } - if len(str) > 0 { - // Send remainder - l.token = str - l.value = zValue - c <- l - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go deleted file mode 100644 index 0b8f282b6..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go +++ /dev/null @@ -1,144 +0,0 @@ -package dns - -import ( - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "math/big" - "strconv" -) - -const format = "Private-key-format: v1.3\n" - -// PrivateKey ... TODO(miek) -type PrivateKey interface { - Sign([]byte, uint8) ([]byte, error) - String(uint8) string -} - -// PrivateKeyString converts a PrivateKey to a string. This string has the same -// format as the private-key-file of BIND9 (Private-key-format: v1.3). -// It needs some info from the key (the algorithm), so its a method of the -// DNSKEY and calls PrivateKey.String(alg). -func (r *DNSKEY) PrivateKeyString(p PrivateKey) string { - return p.String(r.Algorithm) -} - -type RSAPrivateKey rsa.PrivateKey - -func (p *RSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - var hash crypto.Hash - switch alg { - case RSASHA1, RSASHA1NSEC3SHA1: - hash = crypto.SHA1 - case RSASHA256: - hash = crypto.SHA256 - case RSASHA512: - hash = crypto.SHA512 - default: - return nil, ErrAlg - } - return rsa.SignPKCS1v15(nil, (*rsa.PrivateKey)(p), hash, hashed) -} - -func (p *RSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - modulus := toBase64(p.PublicKey.N.Bytes()) - e := big.NewInt(int64(p.PublicKey.E)) - publicExponent := toBase64(e.Bytes()) - privateExponent := toBase64(p.D.Bytes()) - prime1 := toBase64(p.Primes[0].Bytes()) - prime2 := toBase64(p.Primes[1].Bytes()) - // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm - // and from: http://code.google.com/p/go/issues/detail?id=987 - one := big.NewInt(1) - p1 := big.NewInt(0).Sub(p.Primes[0], one) - q1 := big.NewInt(0).Sub(p.Primes[1], one) - exp1 := big.NewInt(0).Mod(p.D, p1) - exp2 := big.NewInt(0).Mod(p.D, q1) - coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0]) - - exponent1 := toBase64(exp1.Bytes()) - exponent2 := toBase64(exp2.Bytes()) - coefficient := toBase64(coeff.Bytes()) - - return format + - "Algorithm: " + algorithm + "\n" + - "Modulus: " + modulus + "\n" + - "PublicExponent: " + publicExponent + "\n" + - "PrivateExponent: " + privateExponent + "\n" + - "Prime1: " + prime1 + "\n" + - "Prime2: " + prime2 + "\n" + - "Exponent1: " + exponent1 + "\n" + - "Exponent2: " + exponent2 + "\n" + - "Coefficient: " + coefficient + "\n" -} - -type ECDSAPrivateKey ecdsa.PrivateKey - -func (p *ECDSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - var intlen int - switch alg { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - default: - return nil, ErrAlg - } - r1, s1, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hashed) - if err != nil { - return nil, err - } - signature := intToBytes(r1, intlen) - signature = append(signature, intToBytes(s1, intlen)...) - return signature, nil -} - -func (p *ECDSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - var intlen int - switch alg { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - } - private := toBase64(intToBytes(p.D, intlen)) - return format + - "Algorithm: " + algorithm + "\n" + - "PrivateKey: " + private + "\n" -} - -type DSAPrivateKey dsa.PrivateKey - -func (p *DSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - r1, s1, err := dsa.Sign(rand.Reader, (*dsa.PrivateKey)(p), hashed) - if err != nil { - return nil, err - } - t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) - signature := []byte{byte(t)} - signature = append(signature, intToBytes(r1, 20)...) - signature = append(signature, intToBytes(s1, 20)...) - return signature, nil -} - -func (p *DSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8) - prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8)) - subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20)) - base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8)) - priv := toBase64(intToBytes(p.X, 20)) - pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8)) - return format + - "Algorithm: " + algorithm + "\n" + - "Prime(p): " + prime + "\n" + - "Subprime(q): " + subprime + "\n" + - "Base(g): " + base + "\n" + - "Private_value(x): " + priv + "\n" + - "Public_value(y): " + pub + "\n" -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go deleted file mode 100644 index 48c22362c..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go +++ /dev/null @@ -1,658 +0,0 @@ -package dns - -import ( - "reflect" - "strings" - "testing" - "time" -) - -func getKey() *DNSKEY { - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz" - return key -} - -func getSoa() *SOA { - soa := new(SOA) - soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0} - soa.Ns = "open.nlnetlabs.nl." - soa.Mbox = "miekg.atoom.net." - soa.Serial = 1293945905 - soa.Refresh = 14400 - soa.Retry = 3600 - soa.Expire = 604800 - soa.Minttl = 86400 - return soa -} - -func TestGenerateEC(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = ECDSAP256SHA256 - privkey, _ := key.Generate(256) - t.Log(key.String()) - t.Log(key.PrivateKeyString(privkey)) -} - -func TestGenerateDSA(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = DSA - privkey, _ := key.Generate(1024) - t.Log(key.String()) - t.Log(key.PrivateKeyString(privkey)) -} - -func TestGenerateRSA(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - privkey, _ := key.Generate(1024) - t.Log(key.String()) - t.Log(key.PrivateKeyString(privkey)) -} - -func TestSecure(t *testing.T) { - soa := getSoa() - - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.TypeCovered = TypeSOA - sig.Algorithm = RSASHA256 - sig.Labels = 2 - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.OrigTtl = 14400 - sig.KeyTag = 12051 - sig.SignerName = "miek.nl." - sig.Signature = "oMCbslaAVIp/8kVtLSms3tDABpcPRUgHLrOR48OOplkYo+8TeEGWwkSwaz/MRo2fB4FxW0qj/hTlIjUGuACSd+b1wKdH5GvzRJc2pFmxtCbm55ygAh4EUL0F6U5cKtGJGSXxxg6UFCQ0doJCmiGFa78LolaUOXImJrk6AFrGa0M=" - - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz" - - // It should validate. Period is checked separately, so this will keep on working - if sig.Verify(key, []RR{soa}) != nil { - t.Error("failure to validate") - } -} - -func TestSignature(t *testing.T) { - sig := new(RRSIG) - sig.Hdr.Name = "miek.nl." - sig.Hdr.Class = ClassINET - sig.Hdr.Ttl = 3600 - sig.TypeCovered = TypeDNSKEY - sig.Algorithm = RSASHA1 - sig.Labels = 2 - sig.OrigTtl = 4000 - sig.Expiration = 1000 //Thu Jan 1 02:06:40 CET 1970 - sig.Inception = 800 //Thu Jan 1 01:13:20 CET 1970 - sig.KeyTag = 34641 - sig.SignerName = "miek.nl." - sig.Signature = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ" - - // Should not be valid - if sig.ValidityPeriod(time.Now()) { - t.Error("should not be valid") - } - - sig.Inception = 315565800 //Tue Jan 1 10:10:00 CET 1980 - sig.Expiration = 4102477800 //Fri Jan 1 10:10:00 CET 2100 - if !sig.ValidityPeriod(time.Now()) { - t.Error("should be valid") - } -} - -func TestSignVerify(t *testing.T) { - // The record we want to sign - soa := new(SOA) - soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0} - soa.Ns = "open.nlnetlabs.nl." - soa.Mbox = "miekg.atoom.net." - soa.Serial = 1293945905 - soa.Refresh = 14400 - soa.Retry = 3600 - soa.Expire = 604800 - soa.Minttl = 86400 - - soa1 := new(SOA) - soa1.Hdr = RR_Header{"*.miek.nl.", TypeSOA, ClassINET, 14400, 0} - soa1.Ns = "open.nlnetlabs.nl." - soa1.Mbox = "miekg.atoom.net." - soa1.Serial = 1293945905 - soa1.Refresh = 14400 - soa1.Retry = 3600 - soa1.Expire = 604800 - soa1.Minttl = 86400 - - srv := new(SRV) - srv.Hdr = RR_Header{"srv.miek.nl.", TypeSRV, ClassINET, 14400, 0} - srv.Port = 1000 - srv.Weight = 800 - srv.Target = "web1.miek.nl." - - // With this key - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - privkey, _ := key.Generate(512) - - // Fill in the values of the Sig, before signing - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.TypeCovered = soa.Hdr.Rrtype - sig.Labels = uint8(CountLabel(soa.Hdr.Name)) // works for all 3 - sig.OrigTtl = soa.Hdr.Ttl - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.KeyTag = key.KeyTag() // Get the keyfrom the Key - sig.SignerName = key.Hdr.Name - sig.Algorithm = RSASHA256 - - for _, r := range []RR{soa, soa1, srv} { - if sig.Sign(privkey, []RR{r}) != nil { - t.Error("failure to sign the record") - continue - } - if sig.Verify(key, []RR{r}) != nil { - t.Error("failure to validate") - continue - } - t.Logf("validated: %s", r.Header().Name) - } -} - -func Test65534(t *testing.T) { - t6 := new(RFC3597) - t6.Hdr = RR_Header{"miek.nl.", 65534, ClassINET, 14400, 0} - t6.Rdata = "505D870001" - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - privkey, _ := key.Generate(1024) - - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.TypeCovered = t6.Hdr.Rrtype - sig.Labels = uint8(CountLabel(t6.Hdr.Name)) - sig.OrigTtl = t6.Hdr.Ttl - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.KeyTag = key.KeyTag() - sig.SignerName = key.Hdr.Name - sig.Algorithm = RSASHA256 - if err := sig.Sign(privkey, []RR{t6}); err != nil { - t.Error(err) - t.Error("failure to sign the TYPE65534 record") - } - if err := sig.Verify(key, []RR{t6}); err != nil { - t.Error(err) - t.Error("failure to validate") - } else { - t.Logf("validated: %s", t6.Header().Name) - } -} - -func TestDnskey(t *testing.T) { - pubkey, err := ReadRR(strings.NewReader(` -miek.nl. IN DNSKEY 256 3 10 AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL ;{id = 5240 (zsk), size = 1024b} -`), "Kmiek.nl.+010+05240.key") - if err != nil { - t.Fatal(err) - } - privStr := `Private-key-format: v1.3 -Algorithm: 10 (RSASHA512) -Modulus: m4wK7YV26AeROtdiCXmqLG9wPDVoMOW8vjr/EkpscEAdjXp81RvZvrlzCSjYmz9onFRgltmTl3AINnFh+t9tlW0M9C5zejxBoKFXELv8ljPYAdz2oe+pDWPhWsfvVFYg2VCjpViPM38EakyE5mhk4TDOnUd+w4TeU1hyhZTWyYs= -PublicExponent: AQAB -PrivateExponent: UfCoIQ/Z38l8vB6SSqOI/feGjHEl/fxIPX4euKf0D/32k30fHbSaNFrFOuIFmWMB3LimWVEs6u3dpbB9CQeCVg7hwU5puG7OtuiZJgDAhNeOnxvo5btp4XzPZrJSxR4WNQnwIiYWbl0aFlL1VGgHC/3By89ENZyWaZcMLW4KGWE= -Prime1: yxwC6ogAu8aVcDx2wg1V0b5M5P6jP8qkRFVMxWNTw60Vkn+ECvw6YAZZBHZPaMyRYZLzPgUlyYRd0cjupy4+fQ== -Prime2: xA1bF8M0RTIQ6+A11AoVG6GIR/aPGg5sogRkIZ7ID/sF6g9HMVU/CM2TqVEBJLRPp73cv6ZeC3bcqOCqZhz+pw== -Exponent1: xzkblyZ96bGYxTVZm2/vHMOXswod4KWIyMoOepK6B/ZPcZoIT6omLCgtypWtwHLfqyCz3MK51Nc0G2EGzg8rFQ== -Exponent2: Pu5+mCEb7T5F+kFNZhQadHUklt0JUHbi3hsEvVoHpEGSw3BGDQrtIflDde0/rbWHgDPM4WQY+hscd8UuTXrvLw== -Coefficient: UuRoNqe7YHnKmQzE6iDWKTMIWTuoqqrFAmXPmKQnC+Y+BQzOVEHUo9bXdDnoI9hzXP1gf8zENMYwYLeWpuYlFQ== -` - privkey, err := pubkey.(*DNSKEY).ReadPrivateKey(strings.NewReader(privStr), - "Kmiek.nl.+010+05240.private") - if err != nil { - t.Fatal(err) - } - if pubkey.(*DNSKEY).PublicKey != "AwEAAZuMCu2FdugHkTrXYgl5qixvcDw1aDDlvL46/xJKbHBAHY16fNUb2b65cwko2Js/aJxUYJbZk5dwCDZxYfrfbZVtDPQuc3o8QaChVxC7/JYz2AHc9qHvqQ1j4VrH71RWINlQo6VYjzN/BGpMhOZoZOEwzp1HfsOE3lNYcoWU1smL" { - t.Error("pubkey is not what we've read") - } - if pubkey.(*DNSKEY).PrivateKeyString(privkey) != privStr { - t.Error("privkey is not what we've read") - t.Errorf("%v", pubkey.(*DNSKEY).PrivateKeyString(privkey)) - } -} - -func TestTag(t *testing.T) { - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 3600 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz" - - tag := key.KeyTag() - if tag != 12051 { - t.Errorf("wrong key tag: %d for key %v", tag, key) - } -} - -func TestKeyRSA(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 3600 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - priv, _ := key.Generate(2048) - - soa := new(SOA) - soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0} - soa.Ns = "open.nlnetlabs.nl." - soa.Mbox = "miekg.atoom.net." - soa.Serial = 1293945905 - soa.Refresh = 14400 - soa.Retry = 3600 - soa.Expire = 604800 - soa.Minttl = 86400 - - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.TypeCovered = TypeSOA - sig.Algorithm = RSASHA256 - sig.Labels = 2 - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.OrigTtl = soa.Hdr.Ttl - sig.KeyTag = key.KeyTag() - sig.SignerName = key.Hdr.Name - - if err := sig.Sign(priv, []RR{soa}); err != nil { - t.Error("failed to sign") - return - } - if err := sig.Verify(key, []RR{soa}); err != nil { - t.Error("failed to verify") - } -} - -func TestKeyToDS(t *testing.T) { - key := new(DNSKEY) - key.Hdr.Name = "miek.nl." - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 3600 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = RSASHA256 - key.PublicKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz" - - ds := key.ToDS(SHA1) - if strings.ToUpper(ds.Digest) != "B5121BDB5B8D86D0CC5FFAFBAAABE26C3E20BAC1" { - t.Errorf("wrong DS digest for SHA1\n%v", ds) - } -} - -func TestSignRSA(t *testing.T) { - pub := "miek.nl. IN DNSKEY 256 3 5 AwEAAb+8lGNCxJgLS8rYVer6EnHVuIkQDghdjdtewDzU3G5R7PbMbKVRvH2Ma7pQyYceoaqWZQirSj72euPWfPxQnMy9ucCylA+FuH9cSjIcPf4PqJfdupHk9X6EBYjxrCLY4p1/yBwgyBIRJtZtAqM3ceAH2WovEJD6rTtOuHo5AluJ" - - priv := `Private-key-format: v1.3 -Algorithm: 5 (RSASHA1) -Modulus: v7yUY0LEmAtLythV6voScdW4iRAOCF2N217APNTcblHs9sxspVG8fYxrulDJhx6hqpZlCKtKPvZ649Z8/FCczL25wLKUD4W4f1xKMhw9/g+ol926keT1foQFiPGsItjinX/IHCDIEhEm1m0Cozdx4AfZai8QkPqtO064ejkCW4k= -PublicExponent: AQAB -PrivateExponent: YPwEmwjk5HuiROKU4xzHQ6l1hG8Iiha4cKRG3P5W2b66/EN/GUh07ZSf0UiYB67o257jUDVEgwCuPJz776zfApcCB4oGV+YDyEu7Hp/rL8KcSN0la0k2r9scKwxTp4BTJT23zyBFXsV/1wRDK1A5NxsHPDMYi2SoK63Enm/1ptk= -Prime1: /wjOG+fD0ybNoSRn7nQ79udGeR1b0YhUA5mNjDx/x2fxtIXzygYk0Rhx9QFfDy6LOBvz92gbNQlzCLz3DJt5hw== -Prime2: wHZsJ8OGhkp5p3mrJFZXMDc2mbYusDVTA+t+iRPdS797Tj0pjvU2HN4vTnTj8KBQp6hmnY7dLp9Y1qserySGbw== -Exponent1: N0A7FsSRIg+IAN8YPQqlawoTtG1t1OkJ+nWrurPootScApX6iMvn8fyvw3p2k51rv84efnzpWAYiC8SUaQDNxQ== -Exponent2: SvuYRaGyvo0zemE3oS+WRm2scxR8eiA8WJGeOc+obwOKCcBgeZblXzfdHGcEC1KaOcetOwNW/vwMA46lpLzJNw== -Coefficient: 8+7ZN/JgByqv0NfULiFKTjtyegUcijRuyij7yNxYbCBneDvZGxJwKNi4YYXWx743pcAj4Oi4Oh86gcmxLs+hGw== -Created: 20110302104537 -Publish: 20110302104537 -Activate: 20110302104537` - - xk, _ := NewRR(pub) - k := xk.(*DNSKEY) - p, err := k.NewPrivateKey(priv) - if err != nil { - t.Error(err) - } - switch priv := p.(type) { - case *RSAPrivateKey: - if 65537 != priv.PublicKey.E { - t.Error("exponenent should be 65537") - } - default: - t.Errorf("we should have read an RSA key: %v", priv) - } - if k.KeyTag() != 37350 { - t.Errorf("keytag should be 37350, got %d %v", k.KeyTag(), k) - } - - soa := new(SOA) - soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0} - soa.Ns = "open.nlnetlabs.nl." - soa.Mbox = "miekg.atoom.net." - soa.Serial = 1293945905 - soa.Refresh = 14400 - soa.Retry = 3600 - soa.Expire = 604800 - soa.Minttl = 86400 - - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.KeyTag = k.KeyTag() - sig.SignerName = k.Hdr.Name - sig.Algorithm = k.Algorithm - - sig.Sign(p, []RR{soa}) - if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" { - t.Errorf("signature is not correct: %v", sig) - } -} - -func TestSignVerifyECDSA(t *testing.T) { - pub := `example.net. 3600 IN DNSKEY 257 3 14 ( - xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1 - w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8 - /uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )` - priv := `Private-key-format: v1.2 -Algorithm: 14 (ECDSAP384SHA384) -PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR` - - eckey, err := NewRR(pub) - if err != nil { - t.Fatal(err) - } - privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv) - if err != nil { - t.Fatal(err) - } - // TODO: Create separate test for this - ds := eckey.(*DNSKEY).ToDS(SHA384) - if ds.KeyTag != 10771 { - t.Fatal("wrong keytag on DS") - } - if ds.Digest != "72d7b62976ce06438e9c0bf319013cf801f09ecc84b8d7e9495f27e305c6a9b0563a9b5f4d288405c3008a946df983d6" { - t.Fatal("wrong DS Digest") - } - a, _ := NewRR("www.example.net. 3600 IN A 192.0.2.1") - sig := new(RRSIG) - sig.Hdr = RR_Header{"example.net.", TypeRRSIG, ClassINET, 14400, 0} - sig.Expiration, _ = StringToTime("20100909102025") - sig.Inception, _ = StringToTime("20100812102025") - sig.KeyTag = eckey.(*DNSKEY).KeyTag() - sig.SignerName = eckey.(*DNSKEY).Hdr.Name - sig.Algorithm = eckey.(*DNSKEY).Algorithm - - if sig.Sign(privkey, []RR{a}) != nil { - t.Fatal("failure to sign the record") - } - - if err := sig.Verify(eckey.(*DNSKEY), []RR{a}); err != nil { - t.Fatalf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v", - eckey.(*DNSKEY).String(), - a.String(), - sig.String(), - eckey.(*DNSKEY).PrivateKeyString(privkey), - err, - ) - } -} - -func TestSignVerifyECDSA2(t *testing.T) { - srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.") - if err != nil { - t.Fatal(err) - } - srv := srv1.(*SRV) - - // With this key - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = ECDSAP256SHA256 - privkey, err := key.Generate(256) - if err != nil { - t.Fatal("failure to generate key") - } - - // Fill in the values of the Sig, before signing - sig := new(RRSIG) - sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} - sig.TypeCovered = srv.Hdr.Rrtype - sig.Labels = uint8(CountLabel(srv.Hdr.Name)) // works for all 3 - sig.OrigTtl = srv.Hdr.Ttl - sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" - sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" - sig.KeyTag = key.KeyTag() // Get the keyfrom the Key - sig.SignerName = key.Hdr.Name - sig.Algorithm = ECDSAP256SHA256 - - if sig.Sign(privkey, []RR{srv}) != nil { - t.Fatal("failure to sign the record") - } - - err = sig.Verify(key, []RR{srv}) - if err != nil { - t.Logf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v", - key.String(), - srv.String(), - sig.String(), - key.PrivateKeyString(privkey), - err, - ) - } -} - -// Here the test vectors from the relevant RFCs are checked. -// rfc6605 6.1 -func TestRFC6605P256(t *testing.T) { - exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 13 ( - GojIhhXUN/u4v54ZQqGSnyhWJwaubCvTmeexv7bR6edb - krSqQpF64cYbcB7wNcP+e+MAnLr+Wi9xMWyQLc8NAA== )` - exPriv := `Private-key-format: v1.2 -Algorithm: 13 (ECDSAP256SHA256) -PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=` - rrDNSKEY, err := NewRR(exDNSKEY) - if err != nil { - t.Fatal(err) - } - priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv) - if err != nil { - t.Fatal(err) - } - - exDS := `example.net. 3600 IN DS 55648 13 2 ( - b4c8c1fe2e7477127b27115656ad6256f424625bf5c1 - e2770ce6d6e37df61d17 )` - rrDS, err := NewRR(exDS) - if err != nil { - t.Fatal(err) - } - ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256) - if !reflect.DeepEqual(ourDS, rrDS.(*DS)) { - t.Errorf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS)) - } - - exA := `www.example.net. 3600 IN A 192.0.2.1` - exRRSIG := `www.example.net. 3600 IN RRSIG A 13 3 3600 ( - 20100909100439 20100812100439 55648 example.net. - qx6wLYqmh+l9oCKTN6qIc+bw6ya+KJ8oMz0YP107epXA - yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )` - rrA, err := NewRR(exA) - if err != nil { - t.Fatal(err) - } - rrRRSIG, err := NewRR(exRRSIG) - if err != nil { - t.Fatal(err) - } - if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil { - t.Errorf("Failure to validate the spec RRSIG: %v", err) - } - - ourRRSIG := &RRSIG{ - Hdr: RR_Header{ - Ttl: rrA.Header().Ttl, - }, - KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(), - SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name, - Algorithm: rrDNSKEY.(*DNSKEY).Algorithm, - } - ourRRSIG.Expiration, _ = StringToTime("20100909100439") - ourRRSIG.Inception, _ = StringToTime("20100812100439") - err = ourRRSIG.Sign(priv, []RR{rrA}) - if err != nil { - t.Fatal(err) - } - - if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil { - t.Errorf("Failure to validate our RRSIG: %v", err) - } - - // Signatures are randomized - rrRRSIG.(*RRSIG).Signature = "" - ourRRSIG.Signature = "" - if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) { - t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG)) - } -} - -// rfc6605 6.2 -func TestRFC6605P384(t *testing.T) { - exDNSKEY := `example.net. 3600 IN DNSKEY 257 3 14 ( - xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1 - w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8 - /uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )` - exPriv := `Private-key-format: v1.2 -Algorithm: 14 (ECDSAP384SHA384) -PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR` - rrDNSKEY, err := NewRR(exDNSKEY) - if err != nil { - t.Fatal(err) - } - priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv) - if err != nil { - t.Fatal(err) - } - - exDS := `example.net. 3600 IN DS 10771 14 4 ( - 72d7b62976ce06438e9c0bf319013cf801f09ecc84b8 - d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94 - 6df983d6 )` - rrDS, err := NewRR(exDS) - if err != nil { - t.Fatal(err) - } - ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384) - if !reflect.DeepEqual(ourDS, rrDS.(*DS)) { - t.Fatalf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS)) - } - - exA := `www.example.net. 3600 IN A 192.0.2.1` - exRRSIG := `www.example.net. 3600 IN RRSIG A 14 3 3600 ( - 20100909102025 20100812102025 10771 example.net. - /L5hDKIvGDyI1fcARX3z65qrmPsVz73QD1Mr5CEqOiLP - 95hxQouuroGCeZOvzFaxsT8Glr74hbavRKayJNuydCuz - WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )` - rrA, err := NewRR(exA) - if err != nil { - t.Fatal(err) - } - rrRRSIG, err := NewRR(exRRSIG) - if err != nil { - t.Fatal(err) - } - if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil { - t.Errorf("Failure to validate the spec RRSIG: %v", err) - } - - ourRRSIG := &RRSIG{ - Hdr: RR_Header{ - Ttl: rrA.Header().Ttl, - }, - KeyTag: rrDNSKEY.(*DNSKEY).KeyTag(), - SignerName: rrDNSKEY.(*DNSKEY).Hdr.Name, - Algorithm: rrDNSKEY.(*DNSKEY).Algorithm, - } - ourRRSIG.Expiration, _ = StringToTime("20100909102025") - ourRRSIG.Inception, _ = StringToTime("20100812102025") - err = ourRRSIG.Sign(priv, []RR{rrA}) - if err != nil { - t.Fatal(err) - } - - if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil { - t.Errorf("Failure to validate our RRSIG: %v", err) - } - - // Signatures are randomized - rrRRSIG.(*RRSIG).Signature = "" - ourRRSIG.Signature = "" - if !reflect.DeepEqual(ourRRSIG, rrRRSIG.(*RRSIG)) { - t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG)) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/doc.go b/Godeps/_workspace/src/github.com/miekg/dns/doc.go deleted file mode 100644 index 90ca6f6e5..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/doc.go +++ /dev/null @@ -1,247 +0,0 @@ -/* -Package dns implements a full featured interface to the Domain Name System. -Server- and client-side programming is supported. -The package allows complete control over what is send out to the DNS. The package -API follows the less-is-more principle, by presenting a small, clean interface. - -The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, -TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing. -Note that domain names MUST be fully qualified, before sending them, unqualified -names in a message will result in a packing failure. - -Resource records are native types. They are not stored in wire format. -Basic usage pattern for creating a new resource record: - - r := new(dns.MX) - r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600} - r.Preference = 10 - r.Mx = "mx.miek.nl." - -Or directly from a string: - - mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") - -Or when the default TTL (3600) and class (IN) suit you: - - mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.") - -Or even: - - mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") - -In the DNS messages are exchanged, these messages contain resource -records (sets). Use pattern for creating a message: - - m := new(dns.Msg) - m.SetQuestion("miek.nl.", dns.TypeMX) - -Or when not certain if the domain name is fully qualified: - - m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX) - -The message m is now a message with the question section set to ask -the MX records for the miek.nl. zone. - -The following is slightly more verbose, but more flexible: - - m1 := new(dns.Msg) - m1.Id = dns.Id() - m1.RecursionDesired = true - m1.Question = make([]dns.Question, 1) - m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} - -After creating a message it can be send. -Basic use pattern for synchronous querying the DNS at a -server configured on 127.0.0.1 and port 53: - - c := new(dns.Client) - in, rtt, err := c.Exchange(m1, "127.0.0.1:53") - -Suppressing -multiple outstanding queries (with the same question, type and class) is as easy as setting: - - c.SingleInflight = true - -If these "advanced" features are not needed, a simple UDP query can be send, -with: - - in, err := dns.Exchange(m1, "127.0.0.1:53") - -When this functions returns you will get dns message. A dns message consists -out of four sections. -The question section: in.Question, the answer section: in.Answer, -the authority section: in.Ns and the additional section: in.Extra. - -Each of these sections (except the Question section) contain a []RR. Basic -use pattern for accessing the rdata of a TXT RR as the first RR in -the Answer section: - - if t, ok := in.Answer[0].(*dns.TXT); ok { - // do something with t.Txt - } - -Domain Name and TXT Character String Representations - -Both domain names and TXT character strings are converted to presentation -form both when unpacked and when converted to strings. - -For TXT character strings, tabs, carriage returns and line feeds will be -converted to \t, \r and \n respectively. Back slashes and quotations marks -will be escaped. Bytes below 32 and above 127 will be converted to \DDD -form. - -For domain names, in addition to the above rules brackets, periods, -spaces, semicolons and the at symbol are escaped. - -DNSSEC - -DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It -uses public key cryptography to sign resource records. The -public keys are stored in DNSKEY records and the signatures in RRSIG records. - -Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit -to an request. - - m := new(dns.Msg) - m.SetEdns0(4096, true) - -Signature generation, signature verification and key generation are all supported. - -DYNAMIC UPDATES - -Dynamic updates reuses the DNS message format, but renames three of -the sections. Question is Zone, Answer is Prerequisite, Authority is -Update, only the Additional is not renamed. See RFC 2136 for the gory details. - -You can set a rather complex set of rules for the existence of absence of -certain resource records or names in a zone to specify if resource records -should be added or removed. The table from RFC 2136 supplemented with the Go -DNS function shows which functions exist to specify the prerequisites. - -3.2.4 - Table Of Metavalues Used In Prerequisite Section - - CLASS TYPE RDATA Meaning Function - -------------------------------------------------------------- - ANY ANY empty Name is in use dns.NameUsed - ANY rrset empty RRset exists (value indep) dns.RRsetUsed - NONE ANY empty Name is not in use dns.NameNotUsed - NONE rrset empty RRset does not exist dns.RRsetNotUsed - zone rrset rr RRset exists (value dep) dns.Used - -The prerequisite section can also be left empty. -If you have decided on the prerequisites you can tell what RRs should -be added or deleted. The next table shows the options you have and -what functions to call. - -3.4.2.6 - Table Of Metavalues Used In Update Section - - CLASS TYPE RDATA Meaning Function - --------------------------------------------------------------- - ANY ANY empty Delete all RRsets from name dns.RemoveName - ANY rrset empty Delete an RRset dns.RemoveRRset - NONE rrset rr Delete an RR from RRset dns.Remove - zone rrset rr Add to an RRset dns.Insert - -TRANSACTION SIGNATURE - -An TSIG or transaction signature adds a HMAC TSIG record to each message sent. -The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512. - -Basic use pattern when querying with a TSIG name "axfr." (note that these key names -must be fully qualified - as they are domain names) and the base64 secret -"so6ZGir4GPAqINNh9U5c3A==": - - c := new(dns.Client) - c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} - m := new(dns.Msg) - m.SetQuestion("miek.nl.", dns.TypeMX) - m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) - ... - // When sending the TSIG RR is calculated and filled in before sending - -When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with -TSIG, this is the basic use pattern. In this example we request an AXFR for -miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A==" -and using the server 176.58.119.54: - - t := new(dns.Transfer) - m := new(dns.Msg) - t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} - m.SetAxfr("miek.nl.") - m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) - c, err := t.In(m, "176.58.119.54:53") - for r := range c { ... } - -You can now read the records from the transfer as they come in. Each envelope is checked with TSIG. -If something is not correct an error is returned. - -Basic use pattern validating and replying to a message that has TSIG set. - - server := &dns.Server{Addr: ":53", Net: "udp"} - server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} - go server.ListenAndServe() - dns.HandleFunc(".", handleRequest) - - func handleRequest(w dns.ResponseWriter, r *dns.Msg) { - m := new(Msg) - m.SetReply(r) - if r.IsTsig() { - if w.TsigStatus() == nil { - // *Msg r has an TSIG record and it was validated - m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) - } else { - // *Msg r has an TSIG records and it was not valided - } - } - w.WriteMsg(m) - } - -PRIVATE RRS - -RFC 6895 sets aside a range of type codes for private use. This range -is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these -can be used, before requesting an official type code from IANA. - -EDNS0 - -EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated -by RFC 6891. It defines an new RR type, the OPT RR, which is then completely -abused. -Basic use pattern for creating an (empty) OPT RR: - - o := new(dns.OPT) - o.Hdr.Name = "." // MUST be the root zone, per definition. - o.Hdr.Rrtype = dns.TypeOPT - -The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) -interfaces. Currently only a few have been standardized: EDNS0_NSID -(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note -that these options may be combined in an OPT RR. -Basic use pattern for a server to check if (and which) options are set: - - // o is a dns.OPT - for _, s := range o.Option { - switch e := s.(type) { - case *dns.EDNS0_NSID: - // do stuff with e.Nsid - case *dns.EDNS0_SUBNET: - // access e.Family, e.Address, etc. - } - } - -SIG(0) - -From RFC 2931: - - SIG(0) provides protection for DNS transactions and requests .... - ... protection for glue records, DNS requests, protection for message headers - on requests and responses, and protection of the overall integrity of a response. - -It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared -secret approach in TSIG. -Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and -RSASHA512. - -Signing subsequent messages in multi-message sessions is not implemented. -*/ -package dns diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dyn_test.go b/Godeps/_workspace/src/github.com/miekg/dns/dyn_test.go deleted file mode 100644 index 09986a5e4..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/dyn_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package dns - -// Find better solution diff --git a/Godeps/_workspace/src/github.com/miekg/dns/edns.go b/Godeps/_workspace/src/github.com/miekg/dns/edns.go deleted file mode 100644 index d2bfecbb2..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/edns.go +++ /dev/null @@ -1,523 +0,0 @@ -package dns - -import ( - "encoding/hex" - "errors" - "net" - "strconv" -) - -// EDNS0 Option codes. -const ( - EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 - EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt - EDNS0NSID = 0x3 // nsid (RFC5001) - EDNS0DAU = 0x5 // DNSSEC Algorithm Understood - EDNS0DHU = 0x6 // DS Hash Understood - EDNS0N3U = 0x7 // NSEC3 Hash Understood - EDNS0SUBNET = 0x8 // client-subnet (RFC6891) - EDNS0EXPIRE = 0x9 // EDNS0 expire - EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET - EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891) - EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891) - _DO = 1 << 15 // dnssec ok -) - -// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. -// See RFC 6891. -type OPT struct { - Hdr RR_Header - Option []EDNS0 `dns:"opt"` -} - -func (rr *OPT) Header() *RR_Header { - return &rr.Hdr -} - -func (rr *OPT) String() string { - s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; " - if rr.Do() { - s += "flags: do; " - } else { - s += "flags: ; " - } - s += "udp: " + strconv.Itoa(int(rr.UDPSize())) - - for _, o := range rr.Option { - switch o.(type) { - case *EDNS0_NSID: - s += "\n; NSID: " + o.String() - h, e := o.pack() - var r string - if e == nil { - for _, c := range h { - r += "(" + string(c) + ")" - } - s += " " + r - } - case *EDNS0_SUBNET: - s += "\n; SUBNET: " + o.String() - if o.(*EDNS0_SUBNET).DraftOption { - s += " (draft)" - } - case *EDNS0_UL: - s += "\n; UPDATE LEASE: " + o.String() - case *EDNS0_LLQ: - s += "\n; LONG LIVED QUERIES: " + o.String() - case *EDNS0_DAU: - s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String() - case *EDNS0_DHU: - s += "\n; DS HASH UNDERSTOOD: " + o.String() - case *EDNS0_N3U: - s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() - case *EDNS0_LOCAL: - s += "\n; LOCAL OPT: " + o.String() - } - } - return s -} - -func (rr *OPT) len() int { - l := rr.Hdr.len() - for i := 0; i < len(rr.Option); i++ { - l += 4 // Account for 2-byte option code and 2-byte option length. - lo, _ := rr.Option[i].pack() - l += len(lo) - } - return l -} - -func (rr *OPT) copy() RR { - return &OPT{*rr.Hdr.copyHeader(), rr.Option} -} - -// return the old value -> delete SetVersion? - -// Version returns the EDNS version used. Only zero is defined. -func (rr *OPT) Version() uint8 { - return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16) -} - -// SetVersion sets the version of EDNS. This is usually zero. -func (rr *OPT) SetVersion(v uint8) { - rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16) -} - -// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL). -func (rr *OPT) ExtendedRcode() uint8 { - return uint8((rr.Hdr.Ttl & 0xFF000000) >> 24) -} - -// SetExtendedRcode sets the EDNS extended RCODE field. -func (rr *OPT) SetExtendedRcode(v uint8) { - rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24) -} - -// UDPSize returns the UDP buffer size. -func (rr *OPT) UDPSize() uint16 { - return rr.Hdr.Class -} - -// SetUDPSize sets the UDP buffer size. -func (rr *OPT) SetUDPSize(size uint16) { - rr.Hdr.Class = size -} - -// Do returns the value of the DO (DNSSEC OK) bit. -func (rr *OPT) Do() bool { - return rr.Hdr.Ttl&_DO == _DO -} - -// SetDo sets the DO (DNSSEC OK) bit. -func (rr *OPT) SetDo() { - rr.Hdr.Ttl |= _DO -} - -// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to -// it. -type EDNS0 interface { - // Option returns the option code for the option. - Option() uint16 - // pack returns the bytes of the option data. - pack() ([]byte, error) - // unpack sets the data as found in the buffer. Is also sets - // the length of the slice as the length of the option data. - unpack([]byte) error - // String returns the string representation of the option. - String() string -} - -// The nsid EDNS0 option is used to retrieve a nameserver -// identifier. When sending a request Nsid must be set to the empty string -// The identifier is an opaque string encoded as hex. -// Basic use pattern for creating an nsid option: -// -// o := new(dns.OPT) -// o.Hdr.Name = "." -// o.Hdr.Rrtype = dns.TypeOPT -// e := new(dns.EDNS0_NSID) -// e.Code = dns.EDNS0NSID -// e.Nsid = "AA" -// o.Option = append(o.Option, e) -type EDNS0_NSID struct { - Code uint16 // Always EDNS0NSID - Nsid string // This string needs to be hex encoded -} - -func (e *EDNS0_NSID) pack() ([]byte, error) { - h, err := hex.DecodeString(e.Nsid) - if err != nil { - return nil, err - } - return h, nil -} - -func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } -func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil } -func (e *EDNS0_NSID) String() string { return string(e.Nsid) } - -// The subnet EDNS0 option is used to give the remote nameserver -// an idea of where the client lives. It can then give back a different -// answer depending on the location or network topology. -// Basic use pattern for creating an subnet option: -// -// o := new(dns.OPT) -// o.Hdr.Name = "." -// o.Hdr.Rrtype = dns.TypeOPT -// e := new(dns.EDNS0_SUBNET) -// e.Code = dns.EDNS0SUBNET -// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6 -// e.NetMask = 32 // 32 for IPV4, 128 for IPv6 -// e.SourceScope = 0 -// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4 -// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6 -// o.Option = append(o.Option, e) -type EDNS0_SUBNET struct { - Code uint16 // Always EDNS0SUBNET - Family uint16 // 1 for IP, 2 for IP6 - SourceNetmask uint8 - SourceScope uint8 - Address net.IP - DraftOption bool // Set to true if using the old (0x50fa) option code -} - -func (e *EDNS0_SUBNET) Option() uint16 { - if e.DraftOption { - return EDNS0SUBNETDRAFT - } - return EDNS0SUBNET -} - -func (e *EDNS0_SUBNET) pack() ([]byte, error) { - b := make([]byte, 4) - b[0], b[1] = packUint16(e.Family) - b[2] = e.SourceNetmask - b[3] = e.SourceScope - switch e.Family { - case 1: - if e.SourceNetmask > net.IPv4len*8 { - return nil, errors.New("dns: bad netmask") - } - ip := make([]byte, net.IPv4len) - a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8)) - for i := 0; i < net.IPv4len; i++ { - if i+1 > len(e.Address) { - break - } - ip[i] = a[i] - } - needLength := e.SourceNetmask / 8 - if e.SourceNetmask%8 > 0 { - needLength++ - } - ip = ip[:needLength] - b = append(b, ip...) - case 2: - if e.SourceNetmask > net.IPv6len*8 { - return nil, errors.New("dns: bad netmask") - } - ip := make([]byte, net.IPv6len) - a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8)) - for i := 0; i < net.IPv6len; i++ { - if i+1 > len(e.Address) { - break - } - ip[i] = a[i] - } - needLength := e.SourceNetmask / 8 - if e.SourceNetmask%8 > 0 { - needLength++ - } - ip = ip[:needLength] - b = append(b, ip...) - default: - return nil, errors.New("dns: bad address family") - } - return b, nil -} - -func (e *EDNS0_SUBNET) unpack(b []byte) error { - lb := len(b) - if lb < 4 { - return ErrBuf - } - e.Family, _ = unpackUint16(b, 0) - e.SourceNetmask = b[2] - e.SourceScope = b[3] - switch e.Family { - case 1: - addr := make([]byte, 4) - for i := 0; i < int(e.SourceNetmask/8); i++ { - if i >= len(addr) || 4+i >= len(b) { - return ErrBuf - } - addr[i] = b[4+i] - } - e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3]) - case 2: - addr := make([]byte, 16) - for i := 0; i < int(e.SourceNetmask/8); i++ { - if i >= len(addr) || 4+i >= len(b) { - return ErrBuf - } - addr[i] = b[4+i] - } - e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4], - addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], - addr[11], addr[12], addr[13], addr[14], addr[15]} - } - return nil -} - -func (e *EDNS0_SUBNET) String() (s string) { - if e.Address == nil { - s = "" - } else if e.Address.To4() != nil { - s = e.Address.String() - } else { - s = "[" + e.Address.String() + "]" - } - s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope)) - return -} - -// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set -// an expiration on an update RR. This is helpful for clients that cannot clean -// up after themselves. This is a draft RFC and more information can be found at -// http://files.dns-sd.org/draft-sekar-dns-ul.txt -// -// o := new(dns.OPT) -// o.Hdr.Name = "." -// o.Hdr.Rrtype = dns.TypeOPT -// e := new(dns.EDNS0_UL) -// e.Code = dns.EDNS0UL -// e.Lease = 120 // in seconds -// o.Option = append(o.Option, e) -type EDNS0_UL struct { - Code uint16 // Always EDNS0UL - Lease uint32 -} - -func (e *EDNS0_UL) Option() uint16 { return EDNS0UL } -func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) } - -// Copied: http://golang.org/src/pkg/net/dnsmsg.go -func (e *EDNS0_UL) pack() ([]byte, error) { - b := make([]byte, 4) - b[0] = byte(e.Lease >> 24) - b[1] = byte(e.Lease >> 16) - b[2] = byte(e.Lease >> 8) - b[3] = byte(e.Lease) - return b, nil -} - -func (e *EDNS0_UL) unpack(b []byte) error { - if len(b) < 4 { - return ErrBuf - } - e.Lease = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]) - return nil -} - -// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 -// Implemented for completeness, as the EDNS0 type code is assigned. -type EDNS0_LLQ struct { - Code uint16 // Always EDNS0LLQ - Version uint16 - Opcode uint16 - Error uint16 - Id uint64 - LeaseLife uint32 -} - -func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ } - -func (e *EDNS0_LLQ) pack() ([]byte, error) { - b := make([]byte, 18) - b[0], b[1] = packUint16(e.Version) - b[2], b[3] = packUint16(e.Opcode) - b[4], b[5] = packUint16(e.Error) - b[6] = byte(e.Id >> 56) - b[7] = byte(e.Id >> 48) - b[8] = byte(e.Id >> 40) - b[9] = byte(e.Id >> 32) - b[10] = byte(e.Id >> 24) - b[11] = byte(e.Id >> 16) - b[12] = byte(e.Id >> 8) - b[13] = byte(e.Id) - b[14] = byte(e.LeaseLife >> 24) - b[15] = byte(e.LeaseLife >> 16) - b[16] = byte(e.LeaseLife >> 8) - b[17] = byte(e.LeaseLife) - return b, nil -} - -func (e *EDNS0_LLQ) unpack(b []byte) error { - if len(b) < 18 { - return ErrBuf - } - e.Version, _ = unpackUint16(b, 0) - e.Opcode, _ = unpackUint16(b, 2) - e.Error, _ = unpackUint16(b, 4) - e.Id = uint64(b[6])<<56 | uint64(b[6+1])<<48 | uint64(b[6+2])<<40 | - uint64(b[6+3])<<32 | uint64(b[6+4])<<24 | uint64(b[6+5])<<16 | uint64(b[6+6])<<8 | uint64(b[6+7]) - e.LeaseLife = uint32(b[14])<<24 | uint32(b[14+1])<<16 | uint32(b[14+2])<<8 | uint32(b[14+3]) - return nil -} - -func (e *EDNS0_LLQ) String() string { - s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) + - " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) + - " " + strconv.FormatUint(uint64(e.LeaseLife), 10) - return s -} - -type EDNS0_DAU struct { - Code uint16 // Always EDNS0DAU - AlgCode []uint8 -} - -func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU } -func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil } -func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil } - -func (e *EDNS0_DAU) String() string { - s := "" - for i := 0; i < len(e.AlgCode); i++ { - if a, ok := AlgorithmToString[e.AlgCode[i]]; ok { - s += " " + a - } else { - s += " " + strconv.Itoa(int(e.AlgCode[i])) - } - } - return s -} - -type EDNS0_DHU struct { - Code uint16 // Always EDNS0DHU - AlgCode []uint8 -} - -func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU } -func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil } -func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil } - -func (e *EDNS0_DHU) String() string { - s := "" - for i := 0; i < len(e.AlgCode); i++ { - if a, ok := HashToString[e.AlgCode[i]]; ok { - s += " " + a - } else { - s += " " + strconv.Itoa(int(e.AlgCode[i])) - } - } - return s -} - -type EDNS0_N3U struct { - Code uint16 // Always EDNS0N3U - AlgCode []uint8 -} - -func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U } -func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil } -func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil } - -func (e *EDNS0_N3U) String() string { - // Re-use the hash map - s := "" - for i := 0; i < len(e.AlgCode); i++ { - if a, ok := HashToString[e.AlgCode[i]]; ok { - s += " " + a - } else { - s += " " + strconv.Itoa(int(e.AlgCode[i])) - } - } - return s -} - -type EDNS0_EXPIRE struct { - Code uint16 // Always EDNS0EXPIRE - Expire uint32 -} - -func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE } -func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) } - -func (e *EDNS0_EXPIRE) pack() ([]byte, error) { - b := make([]byte, 4) - b[0] = byte(e.Expire >> 24) - b[1] = byte(e.Expire >> 16) - b[2] = byte(e.Expire >> 8) - b[3] = byte(e.Expire) - return b, nil -} - -func (e *EDNS0_EXPIRE) unpack(b []byte) error { - if len(b) < 4 { - return ErrBuf - } - e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]) - return nil -} - -// The local EDNS0 option is used for local/experimental purposes. The option -// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND] -// (RFC6891), although any unassigned code can actually be used. The content of -// the option is made available in Data, unaltered. -// Basic use pattern for creating a local option: -// -// o := new(dns.OPT) -// o.Hdr.Name = "." -// o.Hdr.Rrtype = dns.TypeOPT -// e := new(dns.EDNS0_LOCAL) -// e.Code = dns.EDNS0LOCALSTART -// e.Data = []byte{72, 82, 74} -// o.Option = append(o.Option, e) -type EDNS0_LOCAL struct { - Code uint16 - Data []byte -} - -func (e *EDNS0_LOCAL) Option() uint16 { return e.Code } -func (e *EDNS0_LOCAL) String() string { - return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data) -} - -func (e *EDNS0_LOCAL) pack() ([]byte, error) { - b := make([]byte, len(e.Data)) - copied := copy(b, e.Data) - if copied != len(e.Data) { - return nil, ErrBuf - } - return b, nil -} - -func (e *EDNS0_LOCAL) unpack(b []byte) error { - e.Data = make([]byte, len(b)) - copied := copy(e.Data, b) - if copied != len(b) { - return ErrBuf - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/edns_test.go b/Godeps/_workspace/src/github.com/miekg/dns/edns_test.go deleted file mode 100644 index 8ee82ab42..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/edns_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package dns - -import "testing" - -func TestOPTTtl(t *testing.T) { - e := &OPT{} - e.Hdr.Name = "." - e.Hdr.Rrtype = TypeOPT - - if e.Do() { - t.Fail() - } - - e.SetDo() - if !e.Do() { - t.Fail() - } - - oldTtl := e.Hdr.Ttl - - if e.Version() != 0 { - t.Fail() - } - - e.SetVersion(42) - if e.Version() != 42 { - t.Fail() - } - - e.SetVersion(0) - if e.Hdr.Ttl != oldTtl { - t.Fail() - } - - if e.ExtendedRcode() != 0 { - t.Fail() - } - - e.SetExtendedRcode(42) - if e.ExtendedRcode() != 42 { - t.Fail() - } - - e.SetExtendedRcode(0) - if e.Hdr.Ttl != oldTtl { - t.Fail() - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/example_test.go b/Godeps/_workspace/src/github.com/miekg/dns/example_test.go deleted file mode 100644 index 817e17c89..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/example_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package dns_test - -import ( - "errors" - "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns" - "log" - "net" -) - -// Retrieve the MX records for miek.nl. -func ExampleMX() { - config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") - c := new(dns.Client) - m := new(dns.Msg) - m.SetQuestion("miek.nl.", dns.TypeMX) - m.RecursionDesired = true - r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) - if err != nil { - return - } - if r.Rcode != dns.RcodeSuccess { - return - } - for _, a := range r.Answer { - if mx, ok := a.(*dns.MX); ok { - fmt.Printf("%s\n", mx.String()) - } - } -} - -// Retrieve the DNSKEY records of a zone and convert them -// to DS records for SHA1, SHA256 and SHA384. -func ExampleDS(zone string) { - config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") - c := new(dns.Client) - m := new(dns.Msg) - if zone == "" { - zone = "miek.nl" - } - m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY) - m.SetEdns0(4096, true) - r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) - if err != nil { - return - } - if r.Rcode != dns.RcodeSuccess { - return - } - for _, k := range r.Answer { - if key, ok := k.(*dns.DNSKEY); ok { - for _, alg := range []uint8{dns.SHA1, dns.SHA256, dns.SHA384} { - fmt.Printf("%s; %d\n", key.ToDS(alg).String(), key.Flags) - } - } - } -} - -const TypeAPAIR = 0x0F99 - -type APAIR struct { - addr [2]net.IP -} - -func NewAPAIR() dns.PrivateRdata { return new(APAIR) } - -func (rd *APAIR) String() string { return rd.addr[0].String() + " " + rd.addr[1].String() } -func (rd *APAIR) Parse(txt []string) error { - if len(txt) != 2 { - return errors.New("two addresses required for APAIR") - } - for i, s := range txt { - ip := net.ParseIP(s) - if ip == nil { - return errors.New("invalid IP in APAIR text representation") - } - rd.addr[i] = ip - } - return nil -} - -func (rd *APAIR) Pack(buf []byte) (int, error) { - b := append([]byte(rd.addr[0]), []byte(rd.addr[1])...) - n := copy(buf, b) - if n != len(b) { - return n, dns.ErrBuf - } - return n, nil -} - -func (rd *APAIR) Unpack(buf []byte) (int, error) { - ln := net.IPv4len * 2 - if len(buf) != ln { - return 0, errors.New("invalid length of APAIR rdata") - } - cp := make([]byte, ln) - copy(cp, buf) // clone bytes to use them in IPs - - rd.addr[0] = net.IP(cp[:3]) - rd.addr[1] = net.IP(cp[4:]) - - return len(buf), nil -} - -func (rd *APAIR) Copy(dest dns.PrivateRdata) error { - cp := make([]byte, rd.Len()) - _, err := rd.Pack(cp) - if err != nil { - return err - } - - d := dest.(*APAIR) - d.addr[0] = net.IP(cp[:3]) - d.addr[1] = net.IP(cp[4:]) - return nil -} - -func (rd *APAIR) Len() int { - return net.IPv4len * 2 -} - -func ExamplePrivateHandle() { - dns.PrivateHandle("APAIR", TypeAPAIR, NewAPAIR) - defer dns.PrivateHandleRemove(TypeAPAIR) - - rr, err := dns.NewRR("miek.nl. APAIR (1.2.3.4 1.2.3.5)") - if err != nil { - log.Fatal("could not parse APAIR record: ", err) - } - fmt.Println(rr) - // Output: miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 - - m := new(dns.Msg) - m.Id = 12345 - m.SetQuestion("miek.nl.", TypeAPAIR) - m.Answer = append(m.Answer, rr) - - fmt.Println(m) - // ;; opcode: QUERY, status: NOERROR, id: 12345 - // ;; flags: rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 - // - // ;; QUESTION SECTION: - // ;miek.nl. IN APAIR - // - // ;; ANSWER SECTION: - // miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/format.go b/Godeps/_workspace/src/github.com/miekg/dns/format.go deleted file mode 100644 index 1ac1664fe..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/format.go +++ /dev/null @@ -1,96 +0,0 @@ -package dns - -import ( - "net" - "reflect" - "strconv" -) - -// NumField returns the number of rdata fields r has. -func NumField(r RR) int { - return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header -} - -// Field returns the rdata field i as a string. Fields are indexed starting from 1. -// RR types that holds slice data, for instance the NSEC type bitmap will return a single -// string where the types are concatenated using a space. -// Accessing non existing fields will cause a panic. -func Field(r RR, i int) string { - if i == 0 { - return "" - } - d := reflect.ValueOf(r).Elem().Field(i) - switch k := d.Kind(); k { - case reflect.String: - return d.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return strconv.FormatInt(d.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return strconv.FormatUint(d.Uint(), 10) - case reflect.Slice: - switch reflect.ValueOf(r).Elem().Type().Field(i).Tag { - case `dns:"a"`: - // TODO(miek): Hmm store this as 16 bytes - if d.Len() < net.IPv6len { - return net.IPv4(byte(d.Index(0).Uint()), - byte(d.Index(1).Uint()), - byte(d.Index(2).Uint()), - byte(d.Index(3).Uint())).String() - } - return net.IPv4(byte(d.Index(12).Uint()), - byte(d.Index(13).Uint()), - byte(d.Index(14).Uint()), - byte(d.Index(15).Uint())).String() - case `dns:"aaaa"`: - return net.IP{ - byte(d.Index(0).Uint()), - byte(d.Index(1).Uint()), - byte(d.Index(2).Uint()), - byte(d.Index(3).Uint()), - byte(d.Index(4).Uint()), - byte(d.Index(5).Uint()), - byte(d.Index(6).Uint()), - byte(d.Index(7).Uint()), - byte(d.Index(8).Uint()), - byte(d.Index(9).Uint()), - byte(d.Index(10).Uint()), - byte(d.Index(11).Uint()), - byte(d.Index(12).Uint()), - byte(d.Index(13).Uint()), - byte(d.Index(14).Uint()), - byte(d.Index(15).Uint()), - }.String() - case `dns:"nsec"`: - if d.Len() == 0 { - return "" - } - s := Type(d.Index(0).Uint()).String() - for i := 1; i < d.Len(); i++ { - s += " " + Type(d.Index(i).Uint()).String() - } - return s - case `dns:"wks"`: - if d.Len() == 0 { - return "" - } - s := strconv.Itoa(int(d.Index(0).Uint())) - for i := 0; i < d.Len(); i++ { - s += " " + strconv.Itoa(int(d.Index(i).Uint())) - } - return s - default: - // if it does not have a tag its a string slice - fallthrough - case `dns:"txt"`: - if d.Len() == 0 { - return "" - } - s := d.Index(0).String() - for i := 1; i < d.Len(); i++ { - s += " " + d.Index(i).String() - } - return s - } - } - return "" -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/idn/example_test.go b/Godeps/_workspace/src/github.com/miekg/dns/idn/example_test.go deleted file mode 100644 index 1d515f0ef..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/idn/example_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package idn_test - -import ( - "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns/idn" -) - -func ExampleToPunycode() { - name := "インターネット.テスト" - fmt.Printf("%s -> %s", name, idn.ToPunycode(name)) - // Output: インターネット.テスト -> xn--eckucmux0ukc.xn--zckzah -} - -func ExampleFromPunycode() { - name := "xn--mgbaja8a1hpac.xn--mgbachtv" - fmt.Printf("%s -> %s", name, idn.FromPunycode(name)) - // Output: xn--mgbaja8a1hpac.xn--mgbachtv -> الانترنت.اختبار -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go b/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go deleted file mode 100644 index ed02eedf5..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go +++ /dev/null @@ -1,269 +0,0 @@ -// Package idn implements encoding from and to punycode as speficied by RFC 3492. -package idn - -import ( - "bytes" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns" - "strings" - "unicode" -) - -// Implementation idea from RFC itself and from from IDNA::Punycode created by -// Tatsuhiko Miyagawa and released under Perl Artistic -// License in 2002. - -const ( - _MIN rune = 1 - _MAX rune = 26 - _SKEW rune = 38 - _BASE rune = 36 - _BIAS rune = 72 - _N rune = 128 - _DAMP rune = 700 - - _DELIMITER = '-' - _PREFIX = "xn--" -) - -// ToPunycode converts unicode domain names to DNS-appropriate punycode names. -// This function would return incorrect result for strings for non-canonical -// unicode strings. -func ToPunycode(s string) string { - tokens := dns.SplitDomainName(s) - switch { - case s == "": - return "" - case tokens == nil: // s == . - return "." - case s[len(s)-1] == '.': - tokens = append(tokens, "") - } - - for i := range tokens { - tokens[i] = string(encode([]byte(tokens[i]))) - } - return strings.Join(tokens, ".") -} - -// FromPunycode returns unicode domain name from provided punycode string. -func FromPunycode(s string) string { - tokens := dns.SplitDomainName(s) - switch { - case s == "": - return "" - case tokens == nil: // s == . - return "." - case s[len(s)-1] == '.': - tokens = append(tokens, "") - } - for i := range tokens { - tokens[i] = string(decode([]byte(tokens[i]))) - } - return strings.Join(tokens, ".") -} - -// digitval converts single byte into meaningful value that's used to calculate decoded unicode character. -const errdigit = 0xffff - -func digitval(code rune) rune { - switch { - case code >= 'A' && code <= 'Z': - return code - 'A' - case code >= 'a' && code <= 'z': - return code - 'a' - case code >= '0' && code <= '9': - return code - '0' + 26 - } - return errdigit -} - -// lettercode finds BASE36 byte (a-z0-9) based on calculated number. -func lettercode(digit rune) rune { - switch { - case digit >= 0 && digit <= 25: - return digit + 'a' - case digit >= 26 && digit <= 36: - return digit - 26 + '0' - } - panic("dns: not reached") -} - -// adapt calculates next bias to be used for next iteration delta. -func adapt(delta rune, numpoints int, firsttime bool) rune { - if firsttime { - delta /= _DAMP - } else { - delta /= 2 - } - - var k rune - for delta = delta + delta/rune(numpoints); delta > (_BASE-_MIN)*_MAX/2; k += _BASE { - delta /= _BASE - _MIN - } - - return k + ((_BASE-_MIN+1)*delta)/(delta+_SKEW) -} - -// next finds minimal rune (one with lowest codepoint value) that should be equal or above boundary. -func next(b []rune, boundary rune) rune { - if len(b) == 0 { - panic("dns: invalid set of runes to determine next one") - } - m := b[0] - for _, x := range b[1:] { - if x >= boundary && (m < boundary || x < m) { - m = x - } - } - return m -} - -// preprune converts unicode rune to lower case. At this time it's not -// supporting all things described in RFCs -func preprune(r rune) rune { - if unicode.IsUpper(r) { - r = unicode.ToLower(r) - } - return r -} - -// tfunc is a function that helps calculate each character weight -func tfunc(k, bias rune) rune { - switch { - case k <= bias: - return _MIN - case k >= bias+_MAX: - return _MAX - } - return k - bias -} - -// encode transforms Unicode input bytes (that represent DNS label) into punycode bytestream -func encode(input []byte) []byte { - n, bias := _N, _BIAS - - b := bytes.Runes(input) - for i := range b { - b[i] = preprune(b[i]) - } - - basic := make([]byte, 0, len(b)) - for _, ltr := range b { - if ltr <= 0x7f { - basic = append(basic, byte(ltr)) - } - } - basiclen := len(basic) - fulllen := len(b) - if basiclen == fulllen { - return basic - } - - var out bytes.Buffer - - out.WriteString(_PREFIX) - if basiclen > 0 { - out.Write(basic) - out.WriteByte(_DELIMITER) - } - - var ( - ltr, nextltr rune - delta, q rune // delta calculation (see rfc) - t, k, cp rune // weight and codepoint calculation - ) - - s := &bytes.Buffer{} - for h := basiclen; h < fulllen; n, delta = n+1, delta+1 { - nextltr = next(b, n) - s.Truncate(0) - s.WriteRune(nextltr) - delta, n = delta+(nextltr-n)*rune(h+1), nextltr - - for _, ltr = range b { - if ltr < n { - delta++ - } - if ltr == n { - q = delta - for k = _BASE; ; k += _BASE { - t = tfunc(k, bias) - if q < t { - break - } - cp = t + ((q - t) % (_BASE - t)) - out.WriteRune(lettercode(cp)) - q = (q - t) / (_BASE - t) - } - - out.WriteRune(lettercode(q)) - - bias = adapt(delta, h+1, h == basiclen) - h, delta = h+1, 0 - } - } - } - return out.Bytes() -} - -// decode transforms punycode input bytes (that represent DNS label) into Unicode bytestream -func decode(b []byte) []byte { - src := b // b would move and we need to keep it - - n, bias := _N, _BIAS - if !bytes.HasPrefix(b, []byte(_PREFIX)) { - return b - } - out := make([]rune, 0, len(b)) - b = b[len(_PREFIX):] - for pos := len(b) - 1; pos >= 0; pos-- { - // only last delimiter is our interest - if b[pos] == _DELIMITER { - out = append(out, bytes.Runes(b[:pos])...) - b = b[pos+1:] // trim source string - break - } - } - if len(b) == 0 { - return src - } - var ( - i, oldi, w rune - ch byte - t, digit rune - ln int - ) - - for i = 0; len(b) > 0; i++ { - oldi, w = i, 1 - for k := _BASE; len(b) > 0; k += _BASE { - ch, b = b[0], b[1:] - digit = digitval(rune(ch)) - if digit == errdigit { - return src - } - i += digit * w - - t = tfunc(k, bias) - if digit < t { - break - } - - w *= _BASE - t - } - ln = len(out) + 1 - bias = adapt(i-oldi, ln, oldi == 0) - n += i / rune(ln) - i = i % rune(ln) - // insert - out = append(out, 0) - copy(out[i+1:], out[i:]) - out[i] = n - } - - var ret bytes.Buffer - for _, r := range out { - ret.WriteRune(r) - } - return ret.Bytes() -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go b/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go deleted file mode 100644 index 8bf6916a3..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package idn - -import ( - "strings" - "testing" -) - -var testcases = [][2]string{ - {"", ""}, - {"a", "a"}, - {"A-B", "a-b"}, - {"A-B-C", "a-b-c"}, - {"AbC", "abc"}, - {"я", "xn--41a"}, - {"zя", "xn--z-0ub"}, - {"ЯZ", "xn--z-zub"}, - {"а-я", "xn----7sb8g"}, - {"إختبار", "xn--kgbechtv"}, - {"آزمایشی", "xn--hgbk6aj7f53bba"}, - {"测试", "xn--0zwm56d"}, - {"測試", "xn--g6w251d"}, - {"Испытание", "xn--80akhbyknj4f"}, - {"परीक्षा", "xn--11b5bs3a9aj6g"}, - {"δοκιμή", "xn--jxalpdlp"}, - {"테스트", "xn--9t4b11yi5a"}, - {"טעסט", "xn--deba0ad"}, - {"テスト", "xn--zckzah"}, - {"பரிட்சை", "xn--hlcj6aya9esc7a"}, - {"mamão-com-açúcar", "xn--mamo-com-acar-yeb1e6q"}, -} - -func TestEncodeDecodePunycode(t *testing.T) { - for _, tst := range testcases { - enc := encode([]byte(tst[0])) - if string(enc) != tst[1] { - t.Errorf("%s encodeded as %s but should be %s", tst[0], enc, tst[1]) - } - dec := decode([]byte(tst[1])) - if string(dec) != strings.ToLower(tst[0]) { - t.Errorf("%s decoded as %s but should be %s", tst[1], dec, strings.ToLower(tst[0])) - } - } -} - -func TestToFromPunycode(t *testing.T) { - for _, tst := range testcases { - // assert unicode.com == punycode.com - full := ToPunycode(tst[0] + ".com") - if full != tst[1]+".com" { - t.Errorf("invalid result from string conversion to punycode, %s and should be %s.com", full, tst[1]) - } - // assert punycode.punycode == unicode.unicode - decoded := FromPunycode(tst[1] + "." + tst[1]) - if decoded != strings.ToLower(tst[0]+"."+tst[0]) { - t.Errorf("invalid result from string conversion to punycode, %s and should be %s.%s", decoded, tst[0], tst[0]) - } - } -} - -func TestEncodeDecodeFinalPeriod(t *testing.T) { - for _, tst := range testcases { - // assert unicode.com. == punycode.com. - full := ToPunycode(tst[0] + ".") - if full != tst[1]+"." { - t.Errorf("invalid result from string conversion to punycode when period added at the end, %#v and should be %#v", full, tst[1]+".") - } - // assert punycode.com. == unicode.com. - decoded := FromPunycode(tst[1] + ".") - if decoded != strings.ToLower(tst[0]+".") { - t.Errorf("invalid result from string conversion to punycode when period added, %#v and should be %#v", decoded, tst[0]+".") - } - full = ToPunycode(tst[0]) - if full != tst[1] { - t.Errorf("invalid result from string conversion to punycode when no period added at the end, %#v and should be %#v", full, tst[1]+".") - } - // assert punycode.com. == unicode.com. - decoded = FromPunycode(tst[1]) - if decoded != strings.ToLower(tst[0]) { - t.Errorf("invalid result from string conversion to punycode when no period added, %#v and should be %#v", decoded, tst[0]+".") - } - } -} - -var invalid = []string{ - "xn--*", - "xn--", - "xn---", -} - -func TestInvalidPunycode(t *testing.T) { - for _, d := range invalid { - s := FromPunycode(d) - if s != d { - t.Errorf("Changed invalid name %s to %#v", d, s) - } - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/labels.go b/Godeps/_workspace/src/github.com/miekg/dns/labels.go deleted file mode 100644 index 758e5783d..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/labels.go +++ /dev/null @@ -1,162 +0,0 @@ -package dns - -// Holds a bunch of helper functions for dealing with labels. - -// SplitDomainName splits a name string into it's labels. -// www.miek.nl. returns []string{"www", "miek", "nl"} -// The root label (.) returns nil. Note that using -// strings.Split(s) will work in most cases, but does not handle -// escaped dots (\.) for instance. -func SplitDomainName(s string) (labels []string) { - if len(s) == 0 { - return nil - } - fqdnEnd := 0 // offset of the final '.' or the length of the name - idx := Split(s) - begin := 0 - if s[len(s)-1] == '.' { - fqdnEnd = len(s) - 1 - } else { - fqdnEnd = len(s) - } - - switch len(idx) { - case 0: - return nil - case 1: - // no-op - default: - end := 0 - for i := 1; i < len(idx); i++ { - end = idx[i] - labels = append(labels, s[begin:end-1]) - begin = end - } - } - - labels = append(labels, s[begin:fqdnEnd]) - return labels -} - -// CompareDomainName compares the names s1 and s2 and -// returns how many labels they have in common starting from the *right*. -// The comparison stops at the first inequality. The names are not downcased -// before the comparison. -// -// www.miek.nl. and miek.nl. have two labels in common: miek and nl -// www.miek.nl. and www.bla.nl. have one label in common: nl -func CompareDomainName(s1, s2 string) (n int) { - s1 = Fqdn(s1) - s2 = Fqdn(s2) - l1 := Split(s1) - l2 := Split(s2) - - // the first check: root label - if l1 == nil || l2 == nil { - return - } - - j1 := len(l1) - 1 // end - i1 := len(l1) - 2 // start - j2 := len(l2) - 1 - i2 := len(l2) - 2 - // the second check can be done here: last/only label - // before we fall through into the for-loop below - if s1[l1[j1]:] == s2[l2[j2]:] { - n++ - } else { - return - } - for { - if i1 < 0 || i2 < 0 { - break - } - if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] { - n++ - } else { - break - } - j1-- - i1-- - j2-- - i2-- - } - return -} - -// CountLabel counts the the number of labels in the string s. -func CountLabel(s string) (labels int) { - if s == "." { - return - } - off := 0 - end := false - for { - off, end = NextLabel(s, off) - labels++ - if end { - return - } - } - panic("dns: not reached") -} - -// Split splits a name s into its label indexes. -// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}. -// The root name (.) returns nil. Also see dns.SplitDomainName. -func Split(s string) []int { - if s == "." { - return nil - } - idx := make([]int, 1, 3) - off := 0 - end := false - - for { - off, end = NextLabel(s, off) - if end { - return idx - } - idx = append(idx, off) - } - panic("dns: not reached") -} - -// NextLabel returns the index of the start of the next label in the -// string s starting at offset. -// The bool end is true when the end of the string has been reached. -func NextLabel(s string, offset int) (i int, end bool) { - quote := false - for i = offset; i < len(s)-1; i++ { - switch s[i] { - case '\\': - quote = !quote - default: - quote = false - case '.': - if quote { - quote = !quote - continue - } - return i + 1, false - } - } - return i + 1, true -} - -// PrevLabel returns the index of the label when starting from the right and -// jumping n labels to the left. -// The bool start is true when the start of the string has been overshot. -func PrevLabel(s string, n int) (i int, start bool) { - if n == 0 { - return len(s), false - } - lab := Split(s) - if lab == nil { - return 0, true - } - if n > len(lab) { - return 0, true - } - return lab[len(lab)-n], false -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/labels_test.go b/Godeps/_workspace/src/github.com/miekg/dns/labels_test.go deleted file mode 100644 index 2a3f3d05d..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/labels_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package dns - -import ( - "testing" -) - -func TestCompareDomainName(t *testing.T) { - s1 := "www.miek.nl." - s2 := "miek.nl." - s3 := "www.bla.nl." - s4 := "nl.www.bla." - s5 := "nl" - s6 := "miek.nl" - - if CompareDomainName(s1, s2) != 2 { - t.Errorf("%s with %s should be %d", s1, s2, 2) - } - if CompareDomainName(s1, s3) != 1 { - t.Errorf("%s with %s should be %d", s1, s3, 1) - } - if CompareDomainName(s3, s4) != 0 { - t.Errorf("%s with %s should be %d", s3, s4, 0) - } - // Non qualified tests - if CompareDomainName(s1, s5) != 1 { - t.Errorf("%s with %s should be %d", s1, s5, 1) - } - if CompareDomainName(s1, s6) != 2 { - t.Errorf("%s with %s should be %d", s1, s5, 2) - } - - if CompareDomainName(s1, ".") != 0 { - t.Errorf("%s with %s should be %d", s1, s5, 0) - } - if CompareDomainName(".", ".") != 0 { - t.Errorf("%s with %s should be %d", ".", ".", 0) - } -} - -func TestSplit(t *testing.T) { - splitter := map[string]int{ - "www.miek.nl.": 3, - "www.miek.nl": 3, - "www..miek.nl": 4, - `www\.miek.nl.`: 2, - `www\\.miek.nl.`: 3, - ".": 0, - "nl.": 1, - "nl": 1, - "com.": 1, - ".com.": 2, - } - for s, i := range splitter { - if x := len(Split(s)); x != i { - t.Errorf("labels should be %d, got %d: %s %v", i, x, s, Split(s)) - } else { - t.Logf("%s %v", s, Split(s)) - } - } -} - -func TestSplit2(t *testing.T) { - splitter := map[string][]int{ - "www.miek.nl.": []int{0, 4, 9}, - "www.miek.nl": []int{0, 4, 9}, - "nl": []int{0}, - } - for s, i := range splitter { - x := Split(s) - switch len(i) { - case 1: - if x[0] != i[0] { - t.Errorf("labels should be %v, got %v: %s", i, x, s) - } - default: - if x[0] != i[0] || x[1] != i[1] || x[2] != i[2] { - t.Errorf("labels should be %v, got %v: %s", i, x, s) - } - } - } -} - -func TestPrevLabel(t *testing.T) { - type prev struct { - string - int - } - prever := map[prev]int{ - prev{"www.miek.nl.", 0}: 12, - prev{"www.miek.nl.", 1}: 9, - prev{"www.miek.nl.", 2}: 4, - - prev{"www.miek.nl", 0}: 11, - prev{"www.miek.nl", 1}: 9, - prev{"www.miek.nl", 2}: 4, - - prev{"www.miek.nl.", 5}: 0, - prev{"www.miek.nl", 5}: 0, - - prev{"www.miek.nl.", 3}: 0, - prev{"www.miek.nl", 3}: 0, - } - for s, i := range prever { - x, ok := PrevLabel(s.string, s.int) - if i != x { - t.Errorf("label should be %d, got %d, %t: preving %d, %s", i, x, ok, s.int, s.string) - } - } -} - -func TestCountLabel(t *testing.T) { - splitter := map[string]int{ - "www.miek.nl.": 3, - "www.miek.nl": 3, - "nl": 1, - ".": 0, - } - for s, i := range splitter { - x := CountLabel(s) - if x != i { - t.Errorf("CountLabel should have %d, got %d", i, x) - } - } -} - -func TestSplitDomainName(t *testing.T) { - labels := map[string][]string{ - "miek.nl": []string{"miek", "nl"}, - ".": nil, - "www.miek.nl.": []string{"www", "miek", "nl"}, - "www.miek.nl": []string{"www", "miek", "nl"}, - "www..miek.nl": []string{"www", "", "miek", "nl"}, - `www\.miek.nl`: []string{`www\.miek`, "nl"}, - `www\\.miek.nl`: []string{`www\\`, "miek", "nl"}, - } -domainLoop: - for domain, splits := range labels { - parts := SplitDomainName(domain) - if len(parts) != len(splits) { - t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits) - continue domainLoop - } - for i := range parts { - if parts[i] != splits[i] { - t.Errorf("SplitDomainName returned %v for %s, expected %v", parts, domain, splits) - continue domainLoop - } - } - } -} - -func TestIsDomainName(t *testing.T) { - type ret struct { - ok bool - lab int - } - names := map[string]*ret{ - "..": &ret{false, 1}, - "@.": &ret{true, 1}, - "www.example.com": &ret{true, 3}, - "www.e%ample.com": &ret{true, 3}, - "www.example.com.": &ret{true, 3}, - "mi\\k.nl.": &ret{true, 2}, - "mi\\k.nl": &ret{true, 2}, - } - for d, ok := range names { - l, k := IsDomainName(d) - if ok.ok != k || ok.lab != l { - t.Errorf(" got %v %d for %s ", k, l, d) - t.Errorf("have %v %d for %s ", ok.ok, ok.lab, d) - } - } -} - -func BenchmarkSplitLabels(b *testing.B) { - for i := 0; i < b.N; i++ { - Split("www.example.com") - } -} - -func BenchmarkLenLabels(b *testing.B) { - for i := 0; i < b.N; i++ { - CountLabel("www.example.com") - } -} - -func BenchmarkCompareLabels(b *testing.B) { - for i := 0; i < b.N; i++ { - CompareDomainName("www.example.com", "aa.example.com") - } -} - -func BenchmarkIsSubDomain(b *testing.B) { - for i := 0; i < b.N; i++ { - IsSubDomain("www.example.com", "aa.example.com") - IsSubDomain("example.com", "aa.example.com") - IsSubDomain("miek.nl", "aa.example.com") - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/msg.go b/Godeps/_workspace/src/github.com/miekg/dns/msg.go deleted file mode 100644 index 7ccd53192..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/msg.go +++ /dev/null @@ -1,1967 +0,0 @@ -// DNS packet assembly, see RFC 1035. Converting from - Unpack() - -// and to - Pack() - wire format. -// All the packers and unpackers take a (msg []byte, off int) -// and return (off1 int, ok bool). If they return ok==false, they -// also return off1==len(msg), so that the next unpacker will -// also fail. This lets us avoid checks of ok until the end of a -// packing sequence. - -package dns - -import ( - "encoding/base32" - "encoding/base64" - "encoding/hex" - "math/big" - "math/rand" - "net" - "reflect" - "strconv" - "time" -) - -const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer - -var ( - // ErrAlg indicates an error with the (DNSSEC) algorithm. - ErrAlg error = &Error{err: "bad algorithm"} - // ErrAuth indicates an error in the TSIG authentication. - ErrAuth error = &Error{err: "bad authentication"} - // ErrBuf indicates that the buffer used it too small for the message. - ErrBuf error = &Error{err: "buffer size too small"} - // ErrConn indicates that a connection has both a TCP and UDP socket. - ErrConn error = &Error{err: "conn holds both UDP and TCP connection"} - // ErrConnEmpty indicates a connection is being uses before it is initialized. - ErrConnEmpty error = &Error{err: "conn has no connection"} - // ErrExtendedRcode ... - ErrExtendedRcode error = &Error{err: "bad extended rcode"} - // ErrFqdn indicates that a domain name does not have a closing dot. - ErrFqdn error = &Error{err: "domain must be fully qualified"} - // ErrId indicates there is a mismatch with the message's ID. - ErrId error = &Error{err: "id mismatch"} - ErrKeyAlg error = &Error{err: "bad key algorithm"} - ErrKey error = &Error{err: "bad key"} - ErrKeySize error = &Error{err: "bad key size"} - ErrNoSig error = &Error{err: "no signature found"} - ErrPrivKey error = &Error{err: "bad private key"} - ErrRcode error = &Error{err: "bad rcode"} - ErrRdata error = &Error{err: "bad rdata"} - ErrRRset error = &Error{err: "bad rrset"} - ErrSecret error = &Error{err: "no secrets defined"} - ErrShortRead error = &Error{err: "short read"} - // ErrSig indicates that a signature can not be cryptographically validated. - ErrSig error = &Error{err: "bad signature"} - // ErrSigGen indicates a faulure to generate a signature. - ErrSigGen error = &Error{err: "bad signature generation"} - // ErrSOA indicates that no SOA RR was seen when doing zone transfers. - ErrSoa error = &Error{err: "no SOA"} - // ErrTime indicates a timing error in TSIG authentication. - ErrTime error = &Error{err: "bad time"} -) - -// Id, by default, returns a 16 bits random number to be used as a -// message id. The random provided should be good enough. This being a -// variable the function can be reassigned to a custom function. -// For instance, to make it return a static value: -// -// dns.Id = func() uint16 { return 3 } -var Id func() uint16 = id - -// MsgHdr is a a manually-unpacked version of (id, bits). -type MsgHdr struct { - Id uint16 - Response bool - Opcode int - Authoritative bool - Truncated bool - RecursionDesired bool - RecursionAvailable bool - Zero bool - AuthenticatedData bool - CheckingDisabled bool - Rcode int -} - -// Msg contains the layout of a DNS message. -type Msg struct { - MsgHdr - Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format. - Question []Question // Holds the RR(s) of the question section. - Answer []RR // Holds the RR(s) of the answer section. - Ns []RR // Holds the RR(s) of the authority section. - Extra []RR // Holds the RR(s) of the additional section. -} - -// TypeToString is a map of strings for each RR wire type. -var TypeToString = map[uint16]string{ - TypeA: "A", - TypeAAAA: "AAAA", - TypeAFSDB: "AFSDB", - TypeANY: "ANY", // Meta RR - TypeATMA: "ATMA", - TypeAXFR: "AXFR", // Meta RR - TypeCAA: "CAA", - TypeCDNSKEY: "CDNSKEY", - TypeCDS: "CDS", - TypeCERT: "CERT", - TypeCNAME: "CNAME", - TypeDHCID: "DHCID", - TypeDLV: "DLV", - TypeDNAME: "DNAME", - TypeDNSKEY: "DNSKEY", - TypeDS: "DS", - TypeEID: "EID", - TypeEUI48: "EUI48", - TypeEUI64: "EUI64", - TypeGID: "GID", - TypeGPOS: "GPOS", - TypeHINFO: "HINFO", - TypeHIP: "HIP", - TypeIPSECKEY: "IPSECKEY", - TypeISDN: "ISDN", - TypeIXFR: "IXFR", // Meta RR - TypeKEY: "KEY", - TypeKX: "KX", - TypeL32: "L32", - TypeL64: "L64", - TypeLOC: "LOC", - TypeLP: "LP", - TypeMB: "MB", - TypeMD: "MD", - TypeMF: "MF", - TypeMG: "MG", - TypeMINFO: "MINFO", - TypeMR: "MR", - TypeMX: "MX", - TypeNAPTR: "NAPTR", - TypeNID: "NID", - TypeNINFO: "NINFO", - TypeNIMLOC: "NIMLOC", - TypeNS: "NS", - TypeNSAP: "NSAP", - TypeNSAPPTR: "NSAP-PTR", - TypeNSEC3: "NSEC3", - TypeNSEC3PARAM: "NSEC3PARAM", - TypeNSEC: "NSEC", - TypeNULL: "NULL", - TypeOPT: "OPT", - TypeOPENPGPKEY: "OPENPGPKEY", - TypePTR: "PTR", - TypeRKEY: "RKEY", - TypeRP: "RP", - TypeRRSIG: "RRSIG", - TypeRT: "RT", - TypeSIG: "SIG", - TypeSOA: "SOA", - TypeSPF: "SPF", - TypeSRV: "SRV", - TypeSSHFP: "SSHFP", - TypeTA: "TA", - TypeTALINK: "TALINK", - TypeTKEY: "TKEY", // Meta RR - TypeTLSA: "TLSA", - TypeTSIG: "TSIG", // Meta RR - TypeTXT: "TXT", - TypePX: "PX", - TypeUID: "UID", - TypeUINFO: "UINFO", - TypeUNSPEC: "UNSPEC", - TypeURI: "URI", - TypeWKS: "WKS", - TypeX25: "X25", -} - -// StringToType is the reverse of TypeToString, needed for string parsing. -var StringToType = reverseInt16(TypeToString) - -// StringToClass is the reverse of ClassToString, needed for string parsing. -var StringToClass = reverseInt16(ClassToString) - -// Map of opcodes strings. -var StringToOpcode = reverseInt(OpcodeToString) - -// Map of rcodes strings. -var StringToRcode = reverseInt(RcodeToString) - -// ClassToString is a maps Classes to strings for each CLASS wire type. -var ClassToString = map[uint16]string{ - ClassINET: "IN", - ClassCSNET: "CS", - ClassCHAOS: "CH", - ClassHESIOD: "HS", - ClassNONE: "NONE", - ClassANY: "ANY", -} - -// OpcodeToString maps Opcodes to strings. -var OpcodeToString = map[int]string{ - OpcodeQuery: "QUERY", - OpcodeIQuery: "IQUERY", - OpcodeStatus: "STATUS", - OpcodeNotify: "NOTIFY", - OpcodeUpdate: "UPDATE", -} - -// RcodeToString maps Rcodes to strings. -var RcodeToString = map[int]string{ - RcodeSuccess: "NOERROR", - RcodeFormatError: "FORMERR", - RcodeServerFailure: "SERVFAIL", - RcodeNameError: "NXDOMAIN", - RcodeNotImplemented: "NOTIMPL", - RcodeRefused: "REFUSED", - RcodeYXDomain: "YXDOMAIN", // From RFC 2136 - RcodeYXRrset: "YXRRSET", - RcodeNXRrset: "NXRRSET", - RcodeNotAuth: "NOTAUTH", - RcodeNotZone: "NOTZONE", - RcodeBadSig: "BADSIG", // Also known as RcodeBadVers, see RFC 6891 - // RcodeBadVers: "BADVERS", - RcodeBadKey: "BADKEY", - RcodeBadTime: "BADTIME", - RcodeBadMode: "BADMODE", - RcodeBadName: "BADNAME", - RcodeBadAlg: "BADALG", - RcodeBadTrunc: "BADTRUNC", -} - -// Rather than write the usual handful of routines to pack and -// unpack every message that can appear on the wire, we use -// reflection to write a generic pack/unpack for structs and then -// use it. Thus, if in the future we need to define new message -// structs, no new pack/unpack/printing code needs to be written. - -// Domain names are a sequence of counted strings -// split at the dots. They end with a zero-length string. - -// PackDomainName packs a domain name s into msg[off:]. -// If compression is wanted compress must be true and the compression -// map needs to hold a mapping between domain names and offsets -// pointing into msg[]. -func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { - off1, _, err = packDomainName(s, msg, off, compression, compress) - return -} - -func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) { - // special case if msg == nil - lenmsg := 256 - if msg != nil { - lenmsg = len(msg) - } - ls := len(s) - if ls == 0 { // Ok, for instance when dealing with update RR without any rdata. - return off, 0, nil - } - // If not fully qualified, error out, but only if msg == nil #ugly - switch { - case msg == nil: - if s[ls-1] != '.' { - s += "." - ls++ - } - case msg != nil: - if s[ls-1] != '.' { - return lenmsg, 0, ErrFqdn - } - } - // Each dot ends a segment of the name. - // We trade each dot byte for a length byte. - // Except for escaped dots (\.), which are normal dots. - // There is also a trailing zero. - - // Compression - nameoffset := -1 - pointer := -1 - // Emit sequence of counted strings, chopping at dots. - begin := 0 - bs := []byte(s) - roBs, bsFresh, escapedDot := s, true, false - for i := 0; i < ls; i++ { - if bs[i] == '\\' { - for j := i; j < ls-1; j++ { - bs[j] = bs[j+1] - } - ls-- - if off+1 > lenmsg { - return lenmsg, labels, ErrBuf - } - // check for \DDD - if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) { - bs[i] = dddToByte(bs[i:]) - for j := i + 1; j < ls-2; j++ { - bs[j] = bs[j+2] - } - ls -= 2 - } else if bs[i] == 't' { - bs[i] = '\t' - } else if bs[i] == 'r' { - bs[i] = '\r' - } else if bs[i] == 'n' { - bs[i] = '\n' - } - escapedDot = bs[i] == '.' - bsFresh = false - continue - } - - if bs[i] == '.' { - if i > 0 && bs[i-1] == '.' && !escapedDot { - // two dots back to back is not legal - return lenmsg, labels, ErrRdata - } - if i-begin >= 1<<6 { // top two bits of length must be clear - return lenmsg, labels, ErrRdata - } - // off can already (we're in a loop) be bigger than len(msg) - // this happens when a name isn't fully qualified - if off+1 > lenmsg { - return lenmsg, labels, ErrBuf - } - if msg != nil { - msg[off] = byte(i - begin) - } - offset := off - off++ - for j := begin; j < i; j++ { - if off+1 > lenmsg { - return lenmsg, labels, ErrBuf - } - if msg != nil { - msg[off] = bs[j] - } - off++ - } - if compress && !bsFresh { - roBs = string(bs) - bsFresh = true - } - // Dont try to compress '.' - if compress && roBs[begin:] != "." { - if p, ok := compression[roBs[begin:]]; !ok { - // Only offsets smaller than this can be used. - if offset < maxCompressionOffset { - compression[roBs[begin:]] = offset - } - } else { - // The first hit is the longest matching dname - // keep the pointer offset we get back and store - // the offset of the current name, because that's - // where we need to insert the pointer later - - // If compress is true, we're allowed to compress this dname - if pointer == -1 && compress { - pointer = p // Where to point to - nameoffset = offset // Where to point from - break - } - } - } - labels++ - begin = i + 1 - } - escapedDot = false - } - // Root label is special - if len(bs) == 1 && bs[0] == '.' { - return off, labels, nil - } - // If we did compression and we find something add the pointer here - if pointer != -1 { - // We have two bytes (14 bits) to put the pointer in - // if msg == nil, we will never do compression - msg[nameoffset], msg[nameoffset+1] = packUint16(uint16(pointer ^ 0xC000)) - off = nameoffset + 1 - goto End - } - if msg != nil { - msg[off] = 0 - } -End: - off++ - return off, labels, nil -} - -// Unpack a domain name. -// In addition to the simple sequences of counted strings above, -// domain names are allowed to refer to strings elsewhere in the -// packet, to avoid repeating common suffixes when returning -// many entries in a single domain. The pointers are marked -// by a length byte with the top two bits set. Ignoring those -// two bits, that byte and the next give a 14 bit offset from msg[0] -// where we should pick up the trail. -// Note that if we jump elsewhere in the packet, -// we return off1 == the offset after the first pointer we found, -// which is where the next record will start. -// In theory, the pointers are only allowed to jump backward. -// We let them jump anywhere and stop jumping after a while. - -// UnpackDomainName unpacks a domain name into a string. -func UnpackDomainName(msg []byte, off int) (string, int, error) { - s := make([]byte, 0, 64) - off1 := 0 - lenmsg := len(msg) - ptr := 0 // number of pointers followed -Loop: - for { - if off >= lenmsg { - return "", lenmsg, ErrBuf - } - c := int(msg[off]) - off++ - switch c & 0xC0 { - case 0x00: - if c == 0x00 { - // end of name - if len(s) == 0 { - return ".", off, nil - } - break Loop - } - // literal string - if off+c > lenmsg { - return "", lenmsg, ErrBuf - } - for j := off; j < off+c; j++ { - switch b := msg[j]; b { - case '.', '(', ')', ';', ' ', '@': - fallthrough - case '"', '\\': - s = append(s, '\\', b) - case '\t': - s = append(s, '\\', 't') - case '\r': - s = append(s, '\\', 'r') - default: - if b < 32 || b >= 127 { // unprintable use \DDD - var buf [3]byte - bufs := strconv.AppendInt(buf[:0], int64(b), 10) - s = append(s, '\\') - for i := 0; i < 3-len(bufs); i++ { - s = append(s, '0') - } - for _, r := range bufs { - s = append(s, r) - } - } else { - s = append(s, b) - } - } - } - s = append(s, '.') - off += c - case 0xC0: - // pointer to somewhere else in msg. - // remember location after first ptr, - // since that's how many bytes we consumed. - // also, don't follow too many pointers -- - // maybe there's a loop. - if off >= lenmsg { - return "", lenmsg, ErrBuf - } - c1 := msg[off] - off++ - if ptr == 0 { - off1 = off - } - if ptr++; ptr > 10 { - return "", lenmsg, &Error{err: "too many compression pointers"} - } - off = (c^0xC0)<<8 | int(c1) - default: - // 0x80 and 0x40 are reserved - return "", lenmsg, ErrRdata - } - } - if ptr == 0 { - off1 = off - } - return string(s), off1, nil -} - -func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) { - var err error - if len(txt) == 0 { - if offset >= len(msg) { - return offset, ErrBuf - } - msg[offset] = 0 - return offset, nil - } - for i := range txt { - if len(txt[i]) > len(tmp) { - return offset, ErrBuf - } - offset, err = packTxtString(txt[i], msg, offset, tmp) - if err != nil { - return offset, err - } - } - return offset, err -} - -func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) { - lenByteOffset := offset - if offset >= len(msg) { - return offset, ErrBuf - } - offset++ - bs := tmp[:len(s)] - copy(bs, s) - for i := 0; i < len(bs); i++ { - if len(msg) <= offset { - return offset, ErrBuf - } - if bs[i] == '\\' { - i++ - if i == len(bs) { - break - } - // check for \DDD - if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) { - msg[offset] = dddToByte(bs[i:]) - i += 2 - } else if bs[i] == 't' { - msg[offset] = '\t' - } else if bs[i] == 'r' { - msg[offset] = '\r' - } else if bs[i] == 'n' { - msg[offset] = '\n' - } else { - msg[offset] = bs[i] - } - } else { - msg[offset] = bs[i] - } - offset++ - } - l := offset - lenByteOffset - 1 - if l > 255 { - return offset, &Error{err: "string exceeded 255 bytes in txt"} - } - msg[lenByteOffset] = byte(l) - return offset, nil -} - -func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) { - var err error - var ss []string - var s string - for offset < rdend && err == nil { - s, offset, err = unpackTxtString(msg, offset) - if err == nil { - ss = append(ss, s) - } - } - return ss, offset, err -} - -func unpackTxtString(msg []byte, offset int) (string, int, error) { - if offset+1 > len(msg) { - return "", offset, &Error{err: "overflow unpacking txt"} - } - l := int(msg[offset]) - if offset+l+1 > len(msg) { - return "", offset, &Error{err: "overflow unpacking txt"} - } - s := make([]byte, 0, l) - for _, b := range msg[offset+1 : offset+1+l] { - switch b { - case '"', '\\': - s = append(s, '\\', b) - case '\t': - s = append(s, `\t`...) - case '\r': - s = append(s, `\r`...) - case '\n': - s = append(s, `\n`...) - default: - if b < 32 || b > 127 { // unprintable - var buf [3]byte - bufs := strconv.AppendInt(buf[:0], int64(b), 10) - s = append(s, '\\') - for i := 0; i < 3-len(bufs); i++ { - s = append(s, '0') - } - for _, r := range bufs { - s = append(s, r) - } - } else { - s = append(s, b) - } - } - } - offset += 1 + l - return string(s), offset, nil -} - -// Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string, -// slices and other (often anonymous) structs. -func packStructValue(val reflect.Value, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { - var txtTmp []byte - lenmsg := len(msg) - numfield := val.NumField() - for i := 0; i < numfield; i++ { - typefield := val.Type().Field(i) - if typefield.Tag == `dns:"-"` { - continue - } - switch fv := val.Field(i); fv.Kind() { - default: - return lenmsg, &Error{err: "bad kind packing"} - case reflect.Interface: - // PrivateRR is the only RR implementation that has interface field. - // therefore it's expected that this interface would be PrivateRdata - switch data := fv.Interface().(type) { - case PrivateRdata: - n, err := data.Pack(msg[off:]) - if err != nil { - return lenmsg, err - } - off += n - default: - return lenmsg, &Error{err: "bad kind interface packing"} - } - case reflect.Slice: - switch typefield.Tag { - default: - return lenmsg, &Error{"bad tag packing slice: " + typefield.Tag.Get("dns")} - case `dns:"domain-name"`: - for j := 0; j < val.Field(i).Len(); j++ { - element := val.Field(i).Index(j).String() - off, err = PackDomainName(element, msg, off, compression, false && compress) - if err != nil { - return lenmsg, err - } - } - case `dns:"txt"`: - if txtTmp == nil { - txtTmp = make([]byte, 256*4+1) - } - off, err = packTxt(fv.Interface().([]string), msg, off, txtTmp) - if err != nil { - return lenmsg, err - } - case `dns:"opt"`: // edns - for j := 0; j < val.Field(i).Len(); j++ { - element := val.Field(i).Index(j).Interface() - b, e := element.(EDNS0).pack() - if e != nil { - return lenmsg, &Error{err: "overflow packing opt"} - } - // Option code - msg[off], msg[off+1] = packUint16(element.(EDNS0).Option()) - // Length - msg[off+2], msg[off+3] = packUint16(uint16(len(b))) - off += 4 - if off+len(b) > lenmsg { - copy(msg[off:], b) - off = lenmsg - continue - } - // Actual data - copy(msg[off:off+len(b)], b) - off += len(b) - } - case `dns:"a"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, must be 1 - if val.Field(2).Uint() != 1 { - continue - } - } - // It must be a slice of 4, even if it is 16, we encode - // only the first 4 - if off+net.IPv4len > lenmsg { - return lenmsg, &Error{err: "overflow packing a"} - } - switch fv.Len() { - case net.IPv6len: - msg[off] = byte(fv.Index(12).Uint()) - msg[off+1] = byte(fv.Index(13).Uint()) - msg[off+2] = byte(fv.Index(14).Uint()) - msg[off+3] = byte(fv.Index(15).Uint()) - off += net.IPv4len - case net.IPv4len: - msg[off] = byte(fv.Index(0).Uint()) - msg[off+1] = byte(fv.Index(1).Uint()) - msg[off+2] = byte(fv.Index(2).Uint()) - msg[off+3] = byte(fv.Index(3).Uint()) - off += net.IPv4len - case 0: - // Allowed, for dynamic updates - default: - return lenmsg, &Error{err: "overflow packing a"} - } - case `dns:"aaaa"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, must be 2 - if val.Field(2).Uint() != 2 { - continue - } - } - if fv.Len() == 0 { - break - } - if fv.Len() > net.IPv6len || off+fv.Len() > lenmsg { - return lenmsg, &Error{err: "overflow packing aaaa"} - } - for j := 0; j < net.IPv6len; j++ { - msg[off] = byte(fv.Index(j).Uint()) - off++ - } - case `dns:"wks"`: - // TODO(miek): this is wrong should be lenrd - if off == lenmsg { - break // dyn. updates - } - if val.Field(i).Len() == 0 { - break - } - var bitmapbyte uint16 - for j := 0; j < val.Field(i).Len(); j++ { - serv := uint16((fv.Index(j).Uint())) - bitmapbyte = uint16(serv / 8) - if int(bitmapbyte) > lenmsg { - return lenmsg, &Error{err: "overflow packing wks"} - } - bit := uint16(serv) - bitmapbyte*8 - msg[bitmapbyte] = byte(1 << (7 - bit)) - } - off += int(bitmapbyte) - case `dns:"nsec"`: // NSEC/NSEC3 - // This is the uint16 type bitmap - if val.Field(i).Len() == 0 { - // Do absolutely nothing - break - } - - lastwindow := uint16(0) - length := uint16(0) - if off+2 > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx"} - } - for j := 0; j < val.Field(i).Len(); j++ { - t := uint16((fv.Index(j).Uint())) - window := uint16(t / 256) - if lastwindow != window { - // New window, jump to the new offset - off += int(length) + 3 - if off > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} - } - } - length = (t - window*256) / 8 - bit := t - (window * 256) - (length * 8) - if off+2+int(length) > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} - } - - // Setting the window # - msg[off] = byte(window) - // Setting the octets length - msg[off+1] = byte(length + 1) - // Setting the bit value for the type in the right octet - msg[off+2+int(length)] |= byte(1 << (7 - bit)) - lastwindow = window - } - off += 2 + int(length) - off++ - if off > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} - } - } - case reflect.Struct: - off, err = packStructValue(fv, msg, off, compression, compress) - if err != nil { - return lenmsg, err - } - case reflect.Uint8: - if off+1 > lenmsg { - return lenmsg, &Error{err: "overflow packing uint8"} - } - msg[off] = byte(fv.Uint()) - off++ - case reflect.Uint16: - if off+2 > lenmsg { - return lenmsg, &Error{err: "overflow packing uint16"} - } - i := fv.Uint() - msg[off] = byte(i >> 8) - msg[off+1] = byte(i) - off += 2 - case reflect.Uint32: - if off+4 > lenmsg { - return lenmsg, &Error{err: "overflow packing uint32"} - } - i := fv.Uint() - msg[off] = byte(i >> 24) - msg[off+1] = byte(i >> 16) - msg[off+2] = byte(i >> 8) - msg[off+3] = byte(i) - off += 4 - case reflect.Uint64: - switch typefield.Tag { - default: - if off+8 > lenmsg { - return lenmsg, &Error{err: "overflow packing uint64"} - } - i := fv.Uint() - msg[off] = byte(i >> 56) - msg[off+1] = byte(i >> 48) - msg[off+2] = byte(i >> 40) - msg[off+3] = byte(i >> 32) - msg[off+4] = byte(i >> 24) - msg[off+5] = byte(i >> 16) - msg[off+6] = byte(i >> 8) - msg[off+7] = byte(i) - off += 8 - case `dns:"uint48"`: - // Used in TSIG, where it stops at 48 bits, so we discard the upper 16 - if off+6 > lenmsg { - return lenmsg, &Error{err: "overflow packing uint64 as uint48"} - } - i := fv.Uint() - msg[off] = byte(i >> 40) - msg[off+1] = byte(i >> 32) - msg[off+2] = byte(i >> 24) - msg[off+3] = byte(i >> 16) - msg[off+4] = byte(i >> 8) - msg[off+5] = byte(i) - off += 6 - } - case reflect.String: - // There are multiple string encodings. - // The tag distinguishes ordinary strings from domain names. - s := fv.String() - switch typefield.Tag { - default: - return lenmsg, &Error{"bad tag packing string: " + typefield.Tag.Get("dns")} - case `dns:"base64"`: - b64, e := fromBase64([]byte(s)) - if e != nil { - return lenmsg, e - } - copy(msg[off:off+len(b64)], b64) - off += len(b64) - case `dns:"domain-name"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, 1 and 2 or used for addresses - x := val.Field(2).Uint() - if x == 1 || x == 2 { - continue - } - } - if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil { - return lenmsg, err - } - case `dns:"cdomain-name"`: - if off, err = PackDomainName(s, msg, off, compression, true && compress); err != nil { - return lenmsg, err - } - case `dns:"size-base32"`: - // This is purely for NSEC3 atm, the previous byte must - // holds the length of the encoded string. As NSEC3 - // is only defined to SHA1, the hashlength is 20 (160 bits) - msg[off-1] = 20 - fallthrough - case `dns:"base32"`: - b32, e := fromBase32([]byte(s)) - if e != nil { - return lenmsg, e - } - copy(msg[off:off+len(b32)], b32) - off += len(b32) - case `dns:"size-hex"`: - fallthrough - case `dns:"hex"`: - // There is no length encoded here - h, e := hex.DecodeString(s) - if e != nil { - return lenmsg, e - } - if off+hex.DecodedLen(len(s)) > lenmsg { - return lenmsg, &Error{err: "overflow packing hex"} - } - copy(msg[off:off+hex.DecodedLen(len(s))], h) - off += hex.DecodedLen(len(s)) - case `dns:"size"`: - // the size is already encoded in the RR, we can safely use the - // length of string. String is RAW (not encoded in hex, nor base64) - copy(msg[off:off+len(s)], s) - off += len(s) - case `dns:"txt"`: - fallthrough - case "": - if txtTmp == nil { - txtTmp = make([]byte, 256*4+1) - } - off, err = packTxtString(fv.String(), msg, off, txtTmp) - if err != nil { - return lenmsg, err - } - } - } - } - return off, nil -} - -func structValue(any interface{}) reflect.Value { - return reflect.ValueOf(any).Elem() -} - -// PackStruct packs any structure to wire format. -func PackStruct(any interface{}, msg []byte, off int) (off1 int, err error) { - off, err = packStructValue(structValue(any), msg, off, nil, false) - return off, err -} - -func packStructCompress(any interface{}, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { - off, err = packStructValue(structValue(any), msg, off, compression, compress) - return off, err -} - -// TODO(miek): Fix use of rdlength here - -// Unpack a reflect.StructValue from msg. -// Same restrictions as packStructValue. -func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) { - var lenrd int - lenmsg := len(msg) - for i := 0; i < val.NumField(); i++ { - if lenrd != 0 && lenrd == off { - break - } - if off > lenmsg { - return lenmsg, &Error{"bad offset unpacking"} - } - switch fv := val.Field(i); fv.Kind() { - default: - return lenmsg, &Error{err: "bad kind unpacking"} - case reflect.Interface: - // PrivateRR is the only RR implementation that has interface field. - // therefore it's expected that this interface would be PrivateRdata - switch data := fv.Interface().(type) { - case PrivateRdata: - n, err := data.Unpack(msg[off:lenrd]) - if err != nil { - return lenmsg, err - } - off += n - default: - return lenmsg, &Error{err: "bad kind interface unpacking"} - } - case reflect.Slice: - switch val.Type().Field(i).Tag { - default: - return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")} - case `dns:"domain-name"`: - // HIP record slice of name (or none) - var servers []string - var s string - for off < lenrd { - s, off, err = UnpackDomainName(msg, off) - if err != nil { - return lenmsg, err - } - servers = append(servers, s) - } - fv.Set(reflect.ValueOf(servers)) - case `dns:"txt"`: - if off == lenmsg || lenrd == off { - break - } - var txt []string - txt, off, err = unpackTxt(msg, off, lenrd) - if err != nil { - return lenmsg, err - } - fv.Set(reflect.ValueOf(txt)) - case `dns:"opt"`: // edns0 - if off == lenrd { - // This is an EDNS0 (OPT Record) with no rdata - // We can safely return here. - break - } - var edns []EDNS0 - Option: - code := uint16(0) - if off+2 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking opt"} - } - code, off = unpackUint16(msg, off) - optlen, off1 := unpackUint16(msg, off) - if off1+int(optlen) > lenrd { - return lenmsg, &Error{err: "overflow unpacking opt"} - } - switch code { - case EDNS0NSID: - e := new(EDNS0_NSID) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - case EDNS0SUBNET, EDNS0SUBNETDRAFT: - e := new(EDNS0_SUBNET) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - if code == EDNS0SUBNETDRAFT { - e.DraftOption = true - } - case EDNS0UL: - e := new(EDNS0_UL) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - case EDNS0LLQ: - e := new(EDNS0_LLQ) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - case EDNS0DAU: - e := new(EDNS0_DAU) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - case EDNS0DHU: - e := new(EDNS0_DHU) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - case EDNS0N3U: - e := new(EDNS0_N3U) - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - default: - e := new(EDNS0_LOCAL) - e.Code = code - if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { - return lenmsg, err - } - edns = append(edns, e) - off = off1 + int(optlen) - } - if off < lenrd { - goto Option - } - fv.Set(reflect.ValueOf(edns)) - case `dns:"a"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, must be 1 - if val.Field(2).Uint() != 1 { - continue - } - } - if off == lenrd { - break // dyn. update - } - if off+net.IPv4len > lenrd || off+net.IPv4len > lenmsg { - return lenmsg, &Error{err: "overflow unpacking a"} - } - fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3]))) - off += net.IPv4len - case `dns:"aaaa"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, must be 2 - if val.Field(2).Uint() != 2 { - continue - } - } - if off == lenrd { - break - } - if off+net.IPv6len > lenrd || off+net.IPv6len > lenmsg { - return lenmsg, &Error{err: "overflow unpacking aaaa"} - } - fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4], - msg[off+5], msg[off+6], msg[off+7], msg[off+8], msg[off+9], msg[off+10], - msg[off+11], msg[off+12], msg[off+13], msg[off+14], msg[off+15]})) - off += net.IPv6len - case `dns:"wks"`: - // Rest of the record is the bitmap - var serv []uint16 - j := 0 - for off < lenrd { - if off+1 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking wks"} - } - b := msg[off] - // Check the bits one by one, and set the type - if b&0x80 == 0x80 { - serv = append(serv, uint16(j*8+0)) - } - if b&0x40 == 0x40 { - serv = append(serv, uint16(j*8+1)) - } - if b&0x20 == 0x20 { - serv = append(serv, uint16(j*8+2)) - } - if b&0x10 == 0x10 { - serv = append(serv, uint16(j*8+3)) - } - if b&0x8 == 0x8 { - serv = append(serv, uint16(j*8+4)) - } - if b&0x4 == 0x4 { - serv = append(serv, uint16(j*8+5)) - } - if b&0x2 == 0x2 { - serv = append(serv, uint16(j*8+6)) - } - if b&0x1 == 0x1 { - serv = append(serv, uint16(j*8+7)) - } - j++ - off++ - } - fv.Set(reflect.ValueOf(serv)) - case `dns:"nsec"`: // NSEC/NSEC3 - if off == lenrd { - break - } - // Rest of the record is the type bitmap - if off+2 > lenrd || off+2 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } - var nsec []uint16 - length := 0 - window := 0 - for off+2 < lenrd { - window = int(msg[off]) - length = int(msg[off+1]) - //println("off, windows, length, end", off, window, length, endrr) - if length == 0 { - // A length window of zero is strange. If there - // the window should not have been specified. Bail out - // println("dns: length == 0 when unpacking NSEC") - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } - if length > 32 { - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } - - // Walk the bytes in the window - and check the bit settings... - off += 2 - for j := 0; j < length; j++ { - if off+j+1 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } - b := msg[off+j] - // Check the bits one by one, and set the type - if b&0x80 == 0x80 { - nsec = append(nsec, uint16(window*256+j*8+0)) - } - if b&0x40 == 0x40 { - nsec = append(nsec, uint16(window*256+j*8+1)) - } - if b&0x20 == 0x20 { - nsec = append(nsec, uint16(window*256+j*8+2)) - } - if b&0x10 == 0x10 { - nsec = append(nsec, uint16(window*256+j*8+3)) - } - if b&0x8 == 0x8 { - nsec = append(nsec, uint16(window*256+j*8+4)) - } - if b&0x4 == 0x4 { - nsec = append(nsec, uint16(window*256+j*8+5)) - } - if b&0x2 == 0x2 { - nsec = append(nsec, uint16(window*256+j*8+6)) - } - if b&0x1 == 0x1 { - nsec = append(nsec, uint16(window*256+j*8+7)) - } - } - off += length - } - fv.Set(reflect.ValueOf(nsec)) - } - case reflect.Struct: - off, err = unpackStructValue(fv, msg, off) - if err != nil { - return lenmsg, err - } - if val.Type().Field(i).Name == "Hdr" { - lenrd = off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) - } - case reflect.Uint8: - if off == lenmsg { - break - } - if off+1 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking uint8"} - } - fv.SetUint(uint64(uint8(msg[off]))) - off++ - case reflect.Uint16: - if off == lenmsg { - break - } - var i uint16 - if off+2 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking uint16"} - } - i, off = unpackUint16(msg, off) - fv.SetUint(uint64(i)) - case reflect.Uint32: - if off == lenmsg { - break - } - if off+4 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking uint32"} - } - fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]))) - off += 4 - case reflect.Uint64: - switch val.Type().Field(i).Tag { - default: - if off+8 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking uint64"} - } - fv.SetUint(uint64(uint64(msg[off])<<56 | uint64(msg[off+1])<<48 | uint64(msg[off+2])<<40 | - uint64(msg[off+3])<<32 | uint64(msg[off+4])<<24 | uint64(msg[off+5])<<16 | uint64(msg[off+6])<<8 | uint64(msg[off+7]))) - off += 8 - case `dns:"uint48"`: - // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes) - if off+6 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking uint64 as uint48"} - } - fv.SetUint(uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 | - uint64(msg[off+4])<<8 | uint64(msg[off+5]))) - off += 6 - } - case reflect.String: - var s string - if off == lenmsg { - break - } - switch val.Type().Field(i).Tag { - default: - return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")} - case `dns:"hex"`: - hexend := lenrd - if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { - hexend = off + int(val.FieldByName("HitLength").Uint()) - } - if hexend > lenrd || hexend > lenmsg { - return lenmsg, &Error{err: "overflow unpacking hex"} - } - s = hex.EncodeToString(msg[off:hexend]) - off = hexend - case `dns:"base64"`: - // Rest of the RR is base64 encoded value - b64end := lenrd - if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { - b64end = off + int(val.FieldByName("PublicKeyLength").Uint()) - } - if b64end > lenrd || b64end > lenmsg { - return lenmsg, &Error{err: "overflow unpacking base64"} - } - s = toBase64(msg[off:b64end]) - off = b64end - case `dns:"cdomain-name"`: - fallthrough - case `dns:"domain-name"`: - if val.Type().String() == "dns.IPSECKEY" { - // Field(2) is GatewayType, 1 and 2 or used for addresses - x := val.Field(2).Uint() - if x == 1 || x == 2 { - continue - } - } - if off == lenmsg { - // zero rdata foo, OK for dyn. updates - break - } - s, off, err = UnpackDomainName(msg, off) - if err != nil { - return lenmsg, err - } - case `dns:"size-base32"`: - var size int - switch val.Type().Name() { - case "NSEC3": - switch val.Type().Field(i).Name { - case "NextDomain": - name := val.FieldByName("HashLength") - size = int(name.Uint()) - } - } - if off+size > lenmsg { - return lenmsg, &Error{err: "overflow unpacking base32"} - } - s = toBase32(msg[off : off+size]) - off += size - case `dns:"size-hex"`: - // a "size" string, but it must be encoded in hex in the string - var size int - switch val.Type().Name() { - case "NSEC3": - switch val.Type().Field(i).Name { - case "Salt": - name := val.FieldByName("SaltLength") - size = int(name.Uint()) - case "NextDomain": - name := val.FieldByName("HashLength") - size = int(name.Uint()) - } - case "TSIG": - switch val.Type().Field(i).Name { - case "MAC": - name := val.FieldByName("MACSize") - size = int(name.Uint()) - case "OtherData": - name := val.FieldByName("OtherLen") - size = int(name.Uint()) - } - } - if off+size > lenmsg { - return lenmsg, &Error{err: "overflow unpacking hex"} - } - s = hex.EncodeToString(msg[off : off+size]) - off += size - case `dns:"txt"`: - fallthrough - case "": - s, off, err = unpackTxtString(msg, off) - } - fv.SetString(s) - } - } - return off, nil -} - -// Helpers for dealing with escaped bytes -func isDigit(b byte) bool { return b >= '0' && b <= '9' } - -func dddToByte(s []byte) byte { - return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0')) -} - -// UnpackStruct unpacks a binary message from offset off to the interface -// value given. -func UnpackStruct(any interface{}, msg []byte, off int) (int, error) { - return unpackStructValue(structValue(any), msg, off) -} - -// Helper function for packing and unpacking -func intToBytes(i *big.Int, length int) []byte { - buf := i.Bytes() - if len(buf) < length { - b := make([]byte, length) - copy(b[length-len(buf):], buf) - return b - } - return buf -} - -func unpackUint16(msg []byte, off int) (uint16, int) { - return uint16(msg[off])<<8 | uint16(msg[off+1]), off + 2 -} - -func packUint16(i uint16) (byte, byte) { - return byte(i >> 8), byte(i) -} - -func toBase32(b []byte) string { - return base32.HexEncoding.EncodeToString(b) -} - -func fromBase32(s []byte) (buf []byte, err error) { - buflen := base32.HexEncoding.DecodedLen(len(s)) - buf = make([]byte, buflen) - n, err := base32.HexEncoding.Decode(buf, s) - buf = buf[:n] - return -} - -func toBase64(b []byte) string { - return base64.StdEncoding.EncodeToString(b) -} - -func fromBase64(s []byte) (buf []byte, err error) { - buflen := base64.StdEncoding.DecodedLen(len(s)) - buf = make([]byte, buflen) - n, err := base64.StdEncoding.Decode(buf, s) - buf = buf[:n] - return -} - -// PackRR packs a resource record rr into msg[off:]. -// See PackDomainName for documentation about the compression. -func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) { - if rr == nil { - return len(msg), &Error{err: "nil rr"} - } - - off1, err = packStructCompress(rr, msg, off, compression, compress) - if err != nil { - return len(msg), err - } - if rawSetRdlength(msg, off, off1) { - return off1, nil - } - return off, ErrRdata -} - -// UnpackRR unpacks msg[off:] into an RR. -func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) { - // unpack just the header, to find the rr type and length - var h RR_Header - off0 := off - if off, err = UnpackStruct(&h, msg, off); err != nil { - return nil, len(msg), err - } - end := off + int(h.Rdlength) - // make an rr of that type and re-unpack. - mk, known := typeToRR[h.Rrtype] - if !known { - rr = new(RFC3597) - } else { - rr = mk() - } - off, err = UnpackStruct(rr, msg, off0) - if off != end { - return &h, end, &Error{err: "bad rdlength"} - } - return rr, off, err -} - -// Reverse a map -func reverseInt8(m map[uint8]string) map[string]uint8 { - n := make(map[string]uint8) - for u, s := range m { - n[s] = u - } - return n -} - -func reverseInt16(m map[uint16]string) map[string]uint16 { - n := make(map[string]uint16) - for u, s := range m { - n[s] = u - } - return n -} - -func reverseInt(m map[int]string) map[string]int { - n := make(map[string]int) - for u, s := range m { - n[s] = u - } - return n -} - -// Convert a MsgHdr to a string, with dig-like headers: -// -//;; opcode: QUERY, status: NOERROR, id: 48404 -// -//;; flags: qr aa rd ra; -func (h *MsgHdr) String() string { - if h == nil { - return " MsgHdr" - } - - s := ";; opcode: " + OpcodeToString[h.Opcode] - s += ", status: " + RcodeToString[h.Rcode] - s += ", id: " + strconv.Itoa(int(h.Id)) + "\n" - - s += ";; flags:" - if h.Response { - s += " qr" - } - if h.Authoritative { - s += " aa" - } - if h.Truncated { - s += " tc" - } - if h.RecursionDesired { - s += " rd" - } - if h.RecursionAvailable { - s += " ra" - } - if h.Zero { // Hmm - s += " z" - } - if h.AuthenticatedData { - s += " ad" - } - if h.CheckingDisabled { - s += " cd" - } - - s += ";" - return s -} - -// Pack packs a Msg: it is converted to to wire format. -// If the dns.Compress is true the message will be in compressed wire format. -func (dns *Msg) Pack() (msg []byte, err error) { - return dns.PackBuffer(nil) -} - -// PackBuffer packs a Msg, using the given buffer buf. If buf is too small -// a new buffer is allocated. -func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) { - var dh Header - var compression map[string]int - if dns.Compress { - compression = make(map[string]int) // Compression pointer mappings - } - - if dns.Rcode < 0 || dns.Rcode > 0xFFF { - return nil, ErrRcode - } - if dns.Rcode > 0xF { - // Regular RCODE field is 4 bits - opt := dns.IsEdns0() - if opt == nil { - return nil, ErrExtendedRcode - } - opt.SetExtendedRcode(uint8(dns.Rcode >> 4)) - dns.Rcode &= 0xF - } - - // Convert convenient Msg into wire-like Header. - dh.Id = dns.Id - dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode) - if dns.Response { - dh.Bits |= _QR - } - if dns.Authoritative { - dh.Bits |= _AA - } - if dns.Truncated { - dh.Bits |= _TC - } - if dns.RecursionDesired { - dh.Bits |= _RD - } - if dns.RecursionAvailable { - dh.Bits |= _RA - } - if dns.Zero { - dh.Bits |= _Z - } - if dns.AuthenticatedData { - dh.Bits |= _AD - } - if dns.CheckingDisabled { - dh.Bits |= _CD - } - - // Prepare variable sized arrays. - question := dns.Question - answer := dns.Answer - ns := dns.Ns - extra := dns.Extra - - dh.Qdcount = uint16(len(question)) - dh.Ancount = uint16(len(answer)) - dh.Nscount = uint16(len(ns)) - dh.Arcount = uint16(len(extra)) - - // We need the uncompressed length here, because we first pack it and then compress it. - msg = buf - compress := dns.Compress - dns.Compress = false - if packLen := dns.Len() + 1; len(msg) < packLen { - msg = make([]byte, packLen) - } - dns.Compress = compress - - // Pack it in: header and then the pieces. - off := 0 - off, err = packStructCompress(&dh, msg, off, compression, dns.Compress) - if err != nil { - return nil, err - } - for i := 0; i < len(question); i++ { - off, err = packStructCompress(&question[i], msg, off, compression, dns.Compress) - if err != nil { - return nil, err - } - } - for i := 0; i < len(answer); i++ { - off, err = PackRR(answer[i], msg, off, compression, dns.Compress) - if err != nil { - return nil, err - } - } - for i := 0; i < len(ns); i++ { - off, err = PackRR(ns[i], msg, off, compression, dns.Compress) - if err != nil { - return nil, err - } - } - for i := 0; i < len(extra); i++ { - off, err = PackRR(extra[i], msg, off, compression, dns.Compress) - if err != nil { - return nil, err - } - } - return msg[:off], nil -} - -// Unpack unpacks a binary message to a Msg structure. -func (dns *Msg) Unpack(msg []byte) (err error) { - // Header. - var dh Header - off := 0 - if off, err = UnpackStruct(&dh, msg, off); err != nil { - return err - } - dns.Id = dh.Id - dns.Response = (dh.Bits & _QR) != 0 - dns.Opcode = int(dh.Bits>>11) & 0xF - dns.Authoritative = (dh.Bits & _AA) != 0 - dns.Truncated = (dh.Bits & _TC) != 0 - dns.RecursionDesired = (dh.Bits & _RD) != 0 - dns.RecursionAvailable = (dh.Bits & _RA) != 0 - dns.Zero = (dh.Bits & _Z) != 0 - dns.AuthenticatedData = (dh.Bits & _AD) != 0 - dns.CheckingDisabled = (dh.Bits & _CD) != 0 - dns.Rcode = int(dh.Bits & 0xF) - - // Arrays. - dns.Question = make([]Question, dh.Qdcount) - dns.Answer = make([]RR, dh.Ancount) - dns.Ns = make([]RR, dh.Nscount) - dns.Extra = make([]RR, dh.Arcount) - - for i := 0; i < len(dns.Question); i++ { - off, err = UnpackStruct(&dns.Question[i], msg, off) - if err != nil { - return err - } - } - // If we see a TC bit being set we return here, without - // an error, because technically it isn't an error. So return - // without parsing the potentially corrupt packet and hitting an error. - // TODO(miek): this isn't the best strategy! - if dns.Truncated { - dns.Answer = nil - dns.Ns = nil - dns.Extra = nil - return nil - } - for i := 0; i < len(dns.Answer); i++ { - dns.Answer[i], off, err = UnpackRR(msg, off) - if err != nil { - return err - } - } - for i := 0; i < len(dns.Ns); i++ { - dns.Ns[i], off, err = UnpackRR(msg, off) - if err != nil { - return err - } - } - for i := 0; i < len(dns.Extra); i++ { - dns.Extra[i], off, err = UnpackRR(msg, off) - if err != nil { - return err - } - } - if off != len(msg) { - // TODO(miek) make this an error? - // use PackOpt to let people tell how detailed the error reporting should be? - // println("dns: extra bytes in dns packet", off, "<", len(msg)) - } - return nil -} - -// Convert a complete message to a string with dig-like output. -func (dns *Msg) String() string { - if dns == nil { - return " MsgHdr" - } - s := dns.MsgHdr.String() + " " - s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", " - s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", " - s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", " - s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n" - if len(dns.Question) > 0 { - s += "\n;; QUESTION SECTION:\n" - for i := 0; i < len(dns.Question); i++ { - s += dns.Question[i].String() + "\n" - } - } - if len(dns.Answer) > 0 { - s += "\n;; ANSWER SECTION:\n" - for i := 0; i < len(dns.Answer); i++ { - if dns.Answer[i] != nil { - s += dns.Answer[i].String() + "\n" - } - } - } - if len(dns.Ns) > 0 { - s += "\n;; AUTHORITY SECTION:\n" - for i := 0; i < len(dns.Ns); i++ { - if dns.Ns[i] != nil { - s += dns.Ns[i].String() + "\n" - } - } - } - if len(dns.Extra) > 0 { - s += "\n;; ADDITIONAL SECTION:\n" - for i := 0; i < len(dns.Extra); i++ { - if dns.Extra[i] != nil { - s += dns.Extra[i].String() + "\n" - } - } - } - return s -} - -// Len returns the message length when in (un)compressed wire format. -// If dns.Compress is true compression it is taken into account. Len() -// is provided to be a faster way to get the size of the resulting packet, -// than packing it, measuring the size and discarding the buffer. -func (dns *Msg) Len() int { - // We always return one more than needed. - l := 12 // Message header is always 12 bytes - var compression map[string]int - if dns.Compress { - compression = make(map[string]int) - } - for i := 0; i < len(dns.Question); i++ { - l += dns.Question[i].len() - if dns.Compress { - compressionLenHelper(compression, dns.Question[i].Name) - } - } - for i := 0; i < len(dns.Answer); i++ { - l += dns.Answer[i].len() - if dns.Compress { - k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name) - if ok { - l += 1 - k - } - compressionLenHelper(compression, dns.Answer[i].Header().Name) - k, ok = compressionLenSearchType(compression, dns.Answer[i]) - if ok { - l += 1 - k - } - compressionLenHelperType(compression, dns.Answer[i]) - } - } - for i := 0; i < len(dns.Ns); i++ { - l += dns.Ns[i].len() - if dns.Compress { - k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name) - if ok { - l += 1 - k - } - compressionLenHelper(compression, dns.Ns[i].Header().Name) - k, ok = compressionLenSearchType(compression, dns.Ns[i]) - if ok { - l += 1 - k - } - compressionLenHelperType(compression, dns.Ns[i]) - } - } - for i := 0; i < len(dns.Extra); i++ { - l += dns.Extra[i].len() - if dns.Compress { - k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name) - if ok { - l += 1 - k - } - compressionLenHelper(compression, dns.Extra[i].Header().Name) - k, ok = compressionLenSearchType(compression, dns.Extra[i]) - if ok { - l += 1 - k - } - compressionLenHelperType(compression, dns.Extra[i]) - } - } - return l -} - -// Put the parts of the name in the compression map. -func compressionLenHelper(c map[string]int, s string) { - pref := "" - lbs := Split(s) - for j := len(lbs) - 1; j >= 0; j-- { - pref = s[lbs[j]:] - if _, ok := c[pref]; !ok { - c[pref] = len(pref) - } - } -} - -// Look for each part in the compression map and returns its length, -// keep on searching so we get the longest match. -func compressionLenSearch(c map[string]int, s string) (int, bool) { - off := 0 - end := false - if s == "" { // don't bork on bogus data - return 0, false - } - for { - if _, ok := c[s[off:]]; ok { - return len(s[off:]), true - } - if end { - break - } - off, end = NextLabel(s, off) - } - return 0, false -} - -// TODO(miek): should add all types, because the all can be *used* for compression. -func compressionLenHelperType(c map[string]int, r RR) { - switch x := r.(type) { - case *NS: - compressionLenHelper(c, x.Ns) - case *MX: - compressionLenHelper(c, x.Mx) - case *CNAME: - compressionLenHelper(c, x.Target) - case *PTR: - compressionLenHelper(c, x.Ptr) - case *SOA: - compressionLenHelper(c, x.Ns) - compressionLenHelper(c, x.Mbox) - case *MB: - compressionLenHelper(c, x.Mb) - case *MG: - compressionLenHelper(c, x.Mg) - case *MR: - compressionLenHelper(c, x.Mr) - case *MF: - compressionLenHelper(c, x.Mf) - case *MD: - compressionLenHelper(c, x.Md) - case *RT: - compressionLenHelper(c, x.Host) - case *MINFO: - compressionLenHelper(c, x.Rmail) - compressionLenHelper(c, x.Email) - case *AFSDB: - compressionLenHelper(c, x.Hostname) - } -} - -// Only search on compressing these types. -func compressionLenSearchType(c map[string]int, r RR) (int, bool) { - switch x := r.(type) { - case *NS: - return compressionLenSearch(c, x.Ns) - case *MX: - return compressionLenSearch(c, x.Mx) - case *CNAME: - return compressionLenSearch(c, x.Target) - case *PTR: - return compressionLenSearch(c, x.Ptr) - case *SOA: - k, ok := compressionLenSearch(c, x.Ns) - k1, ok1 := compressionLenSearch(c, x.Mbox) - if !ok && !ok1 { - return 0, false - } - return k + k1, true - case *MB: - return compressionLenSearch(c, x.Mb) - case *MG: - return compressionLenSearch(c, x.Mg) - case *MR: - return compressionLenSearch(c, x.Mr) - case *MF: - return compressionLenSearch(c, x.Mf) - case *MD: - return compressionLenSearch(c, x.Md) - case *RT: - return compressionLenSearch(c, x.Host) - case *MINFO: - k, ok := compressionLenSearch(c, x.Rmail) - k1, ok1 := compressionLenSearch(c, x.Email) - if !ok && !ok1 { - return 0, false - } - return k + k1, true - case *AFSDB: - return compressionLenSearch(c, x.Hostname) - } - return 0, false -} - -// id returns a 16 bits random number to be used as a -// message id. The random provided should be good enough. -func id() uint16 { - return uint16(rand.Int()) ^ uint16(time.Now().Nanosecond()) -} - -// Copy returns a new RR which is a deep-copy of r. -func Copy(r RR) RR { - r1 := r.copy() - return r1 -} - -// Copy returns a new *Msg which is a deep-copy of dns. -func (dns *Msg) Copy() *Msg { - return dns.CopyTo(new(Msg)) -} - -// CopyTo copies the contents to the provided message using a deep-copy and returns the copy. -func (dns *Msg) CopyTo(r1 *Msg) *Msg { - r1.MsgHdr = dns.MsgHdr - r1.Compress = dns.Compress - - if len(dns.Question) > 0 { - r1.Question = make([]Question, len(dns.Question)) - copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy - } - - rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra)) - var rri int - - if len(dns.Answer) > 0 { - rrbegin := rri - for i := 0; i < len(dns.Answer); i++ { - rrArr[rri] = dns.Answer[i].copy() - rri++ - } - r1.Answer = rrArr[rrbegin:rri:rri] - } - - if len(dns.Ns) > 0 { - rrbegin := rri - for i := 0; i < len(dns.Ns); i++ { - rrArr[rri] = dns.Ns[i].copy() - rri++ - } - r1.Ns = rrArr[rrbegin:rri:rri] - } - - if len(dns.Extra) > 0 { - rrbegin := rri - for i := 0; i < len(dns.Extra); i++ { - rrArr[rri] = dns.Extra[i].copy() - rri++ - } - r1.Extra = rrArr[rrbegin:rri:rri] - } - - return r1 -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/nsecx.go b/Godeps/_workspace/src/github.com/miekg/dns/nsecx.go deleted file mode 100644 index d2392c6ec..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/nsecx.go +++ /dev/null @@ -1,112 +0,0 @@ -package dns - -import ( - "crypto/sha1" - "hash" - "io" - "strings" -) - -type saltWireFmt struct { - Salt string `dns:"size-hex"` -} - -// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in -// uppercase. -func HashName(label string, ha uint8, iter uint16, salt string) string { - saltwire := new(saltWireFmt) - saltwire.Salt = salt - wire := make([]byte, DefaultMsgSize) - n, err := PackStruct(saltwire, wire, 0) - if err != nil { - return "" - } - wire = wire[:n] - name := make([]byte, 255) - off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false) - if err != nil { - return "" - } - name = name[:off] - var s hash.Hash - switch ha { - case SHA1: - s = sha1.New() - default: - return "" - } - - // k = 0 - name = append(name, wire...) - io.WriteString(s, string(name)) - nsec3 := s.Sum(nil) - // k > 0 - for k := uint16(0); k < iter; k++ { - s.Reset() - nsec3 = append(nsec3, wire...) - io.WriteString(s, string(nsec3)) - nsec3 = s.Sum(nil) - } - return toBase32(nsec3) -} - -// Denialer is an interface that should be implemented by types that are used to denial -// answers in DNSSEC. -type Denialer interface { - // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3. - Cover(name string) bool - // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3. - Match(name string) bool -} - -// Cover implements the Denialer interface. -func (rr *NSEC) Cover(name string) bool { - return true -} - -// Match implements the Denialer interface. -func (rr *NSEC) Match(name string) bool { - return true -} - -// Cover implements the Denialer interface. -func (rr *NSEC3) Cover(name string) bool { - // FIXME(miek): check if the zones match - // FIXME(miek): check if we're not dealing with parent nsec3 - hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) - labels := Split(rr.Hdr.Name) - if len(labels) < 2 { - return false - } - hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot - if hash == rr.NextDomain { - return false // empty interval - } - if hash > rr.NextDomain { // last name, points to apex - // hname > hash - // hname > rr.NextDomain - // TODO(miek) - } - if hname <= hash { - return false - } - if hname >= rr.NextDomain { - return false - } - return true -} - -// Match implements the Denialer interface. -func (rr *NSEC3) Match(name string) bool { - // FIXME(miek): Check if we are in the same zone - hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) - labels := Split(rr.Hdr.Name) - if len(labels) < 2 { - return false - } - hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the . - if hash == hname { - return true - } - return false -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/nsecx_test.go b/Godeps/_workspace/src/github.com/miekg/dns/nsecx_test.go deleted file mode 100644 index 93e0c63fc..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/nsecx_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package dns - -import ( - "testing" -) - -func TestPackNsec3(t *testing.T) { - nsec3 := HashName("dnsex.nl.", SHA1, 0, "DEAD") - if nsec3 != "ROCCJAE8BJJU7HN6T7NG3TNM8ACRS87J" { - t.Error(nsec3) - } - - nsec3 = HashName("a.b.c.example.org.", SHA1, 2, "DEAD") - if nsec3 != "6LQ07OAHBTOOEU2R9ANI2AT70K5O0RCG" { - t.Error(nsec3) - } -} - -func TestNsec3(t *testing.T) { - // examples taken from .nl - nsec3, _ := NewRR("39p91242oslggest5e6a7cci4iaeqvnk.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6 NS DS RRSIG") - if !nsec3.(*NSEC3).Cover("snasajsksasasa.nl.") { // 39p94jrinub66hnpem8qdpstrec86pg3 - t.Error("39p94jrinub66hnpem8qdpstrec86pg3. should be covered by 39p91242oslggest5e6a7cci4iaeqvnk.nl. - 39P99DCGG0MDLARTCRMCF6OFLLUL7PR6") - } - nsec3, _ = NewRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM") - if !nsec3.(*NSEC3).Match("nl.") { // sk4e8fj94u78smusb40o1n0oltbblu2r.nl. - t.Error("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.") - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go b/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go deleted file mode 100644 index c04a9764a..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go +++ /dev/null @@ -1,1378 +0,0 @@ -package dns - -import ( - "bytes" - "crypto/rsa" - "encoding/hex" - "fmt" - "math/rand" - "net" - "reflect" - "strconv" - "strings" - "testing" - "testing/quick" - "time" -) - -func TestDotInName(t *testing.T) { - buf := make([]byte, 20) - PackDomainName("aa\\.bb.nl.", buf, 0, nil, false) - // index 3 must be a real dot - if buf[3] != '.' { - t.Error("dot should be a real dot") - } - - if buf[6] != 2 { - t.Error("this must have the value 2") - } - dom, _, _ := UnpackDomainName(buf, 0) - // printing it should yield the backspace again - if dom != "aa\\.bb.nl." { - t.Error("dot should have been escaped: ", dom) - } -} - -func TestDotLastInLabel(t *testing.T) { - sample := "aa\\..au." - buf := make([]byte, 20) - _, err := PackDomainName(sample, buf, 0, nil, false) - if err != nil { - t.Fatalf("unexpected error packing domain: %v", err) - } - dom, _, _ := UnpackDomainName(buf, 0) - if dom != sample { - t.Fatalf("unpacked domain `%s' doesn't match packed domain", dom) - } -} - -func TestTooLongDomainName(t *testing.T) { - l := "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt." - dom := l + l + l + l + l + l + l - _, err := NewRR(dom + " IN A 127.0.0.1") - if err == nil { - t.Error("should be too long") - } else { - t.Logf("error is %v", err) - } - _, err = NewRR("..com. IN A 127.0.0.1") - if err == nil { - t.Error("should fail") - } else { - t.Logf("error is %v", err) - } -} - -func TestDomainName(t *testing.T) { - tests := []string{"r\\.gieben.miek.nl.", "www\\.www.miek.nl.", - "www.*.miek.nl.", "www.*.miek.nl.", - } - dbuff := make([]byte, 40) - - for _, ts := range tests { - if _, err := PackDomainName(ts, dbuff, 0, nil, false); err != nil { - t.Error("not a valid domain name") - continue - } - n, _, err := UnpackDomainName(dbuff, 0) - if err != nil { - t.Error("failed to unpack packed domain name") - continue - } - if ts != n { - t.Errorf("must be equal: in: %s, out: %s", ts, n) - } - } -} - -func TestDomainNameAndTXTEscapes(t *testing.T) { - tests := []byte{'.', '(', ')', ';', ' ', '@', '"', '\\', '\t', '\r', '\n', 0, 255} - for _, b := range tests { - rrbytes := []byte{ - 1, b, 0, // owner - byte(TypeTXT >> 8), byte(TypeTXT), - byte(ClassINET >> 8), byte(ClassINET), - 0, 0, 0, 1, // TTL - 0, 2, 1, b, // Data - } - rr1, _, err := UnpackRR(rrbytes, 0) - if err != nil { - panic(err) - } - s := rr1.String() - rr2, err := NewRR(s) - if err != nil { - t.Errorf("Error parsing unpacked RR's string: %v", err) - t.Errorf(" Bytes: %v", rrbytes) - t.Errorf("String: %v", s) - } - repacked := make([]byte, len(rrbytes)) - if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil { - t.Errorf("error packing parsed RR: %v", err) - t.Errorf(" original Bytes: %v", rrbytes) - t.Errorf("unpacked Struct: %v", rr1) - t.Errorf(" parsed Struct: %v", rr2) - } - if !bytes.Equal(repacked, rrbytes) { - t.Error("packed bytes don't match original bytes") - t.Errorf(" original bytes: %v", rrbytes) - t.Errorf(" packed bytes: %v", repacked) - t.Errorf("unpacked struct: %v", rr1) - t.Errorf(" parsed struct: %v", rr2) - } - } -} - -func TestTXTEscapeParsing(t *testing.T) { - test := [][]string{ - {`";"`, `";"`}, - {`\;`, `";"`}, - {`"\t"`, `"\t"`}, - {`"\r"`, `"\r"`}, - {`"\ "`, `" "`}, - {`"\;"`, `";"`}, - {`"\;\""`, `";\""`}, - {`"\(a\)"`, `"(a)"`}, - {`"\(a)"`, `"(a)"`}, - {`"(a\)"`, `"(a)"`}, - {`"(a)"`, `"(a)"`}, - {`"\048"`, `"0"`}, - {`"\` + "\n" + `"`, `"\n"`}, - {`"\` + "\r" + `"`, `"\r"`}, - {`"\` + "\x11" + `"`, `"\017"`}, - {`"\'"`, `"'"`}, - } - for _, s := range test { - rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0])) - if err != nil { - t.Errorf("Could not parse %v TXT: %s", s[0], err) - continue - } - - txt := sprintTxt(rr.(*TXT).Txt) - if txt != s[1] { - t.Errorf("Mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1]) - } - } -} - -func GenerateDomain(r *rand.Rand, size int) []byte { - dnLen := size % 70 // artificially limit size so there's less to intrepret if a failure occurs - var dn []byte - done := false - for i := 0; i < dnLen && !done; { - max := dnLen - i - if max > 63 { - max = 63 - } - lLen := max - if lLen != 0 { - lLen = int(r.Int31()) % max - } - done = lLen == 0 - if done { - continue - } - l := make([]byte, lLen+1) - l[0] = byte(lLen) - for j := 0; j < lLen; j++ { - l[j+1] = byte(rand.Int31()) - } - dn = append(dn, l...) - i += 1 + lLen - } - return append(dn, 0) -} - -func TestDomainQuick(t *testing.T) { - r := rand.New(rand.NewSource(0)) - f := func(l int) bool { - db := GenerateDomain(r, l) - ds, _, err := UnpackDomainName(db, 0) - if err != nil { - panic(err) - } - buf := make([]byte, 255) - off, err := PackDomainName(ds, buf, 0, nil, false) - if err != nil { - t.Errorf("error packing domain: %v", err) - t.Errorf(" bytes: %v", db) - t.Errorf("string: %v", ds) - return false - } - if !bytes.Equal(db, buf[:off]) { - t.Errorf("repacked domain doesn't match original:") - t.Errorf("src bytes: %v", db) - t.Errorf(" string: %v", ds) - t.Errorf("out bytes: %v", buf[:off]) - return false - } - return true - } - if err := quick.Check(f, nil); err != nil { - t.Error(err) - } -} - -func GenerateTXT(r *rand.Rand, size int) []byte { - rdLen := size % 300 // artificially limit size so there's less to intrepret if a failure occurs - var rd []byte - for i := 0; i < rdLen; { - max := rdLen - 1 - if max > 255 { - max = 255 - } - sLen := max - if max != 0 { - sLen = int(r.Int31()) % max - } - s := make([]byte, sLen+1) - s[0] = byte(sLen) - for j := 0; j < sLen; j++ { - s[j+1] = byte(rand.Int31()) - } - rd = append(rd, s...) - i += 1 + sLen - } - return rd -} - -// Ok, 2 things. 1) this test breaks with the new functionality of splitting up larger txt -// chunks into 255 byte pieces. 2) I don't like the random nature of this thing, because I can't -// place the quotes where they need to be. -// So either add some code the places the quotes in just the right spots, make this non random -// or do something else. -// Disabled for now. (miek) -func testTXTRRQuick(t *testing.T) { - s := rand.NewSource(0) - r := rand.New(s) - typeAndClass := []byte{ - byte(TypeTXT >> 8), byte(TypeTXT), - byte(ClassINET >> 8), byte(ClassINET), - 0, 0, 0, 1, // TTL - } - f := func(l int) bool { - owner := GenerateDomain(r, l) - rdata := GenerateTXT(r, l) - rrbytes := make([]byte, 0, len(owner)+2+2+4+2+len(rdata)) - rrbytes = append(rrbytes, owner...) - rrbytes = append(rrbytes, typeAndClass...) - rrbytes = append(rrbytes, byte(len(rdata)>>8)) - rrbytes = append(rrbytes, byte(len(rdata))) - rrbytes = append(rrbytes, rdata...) - rr, _, err := UnpackRR(rrbytes, 0) - if err != nil { - panic(err) - } - buf := make([]byte, len(rrbytes)*3) - off, err := PackRR(rr, buf, 0, nil, false) - if err != nil { - t.Errorf("pack Error: %v\nRR: %v", err, rr) - return false - } - buf = buf[:off] - if !bytes.Equal(buf, rrbytes) { - t.Errorf("packed bytes don't match original bytes") - t.Errorf("src bytes: %v", rrbytes) - t.Errorf(" struct: %v", rr) - t.Errorf("out bytes: %v", buf) - return false - } - if len(rdata) == 0 { - // string'ing won't produce any data to parse - return true - } - rrString := rr.String() - rr2, err := NewRR(rrString) - if err != nil { - t.Errorf("error parsing own output: %v", err) - t.Errorf("struct: %v", rr) - t.Errorf("string: %v", rrString) - return false - } - if rr2.String() != rrString { - t.Errorf("parsed rr.String() doesn't match original string") - t.Errorf("original: %v", rrString) - t.Errorf(" parsed: %v", rr2.String()) - return false - } - - buf = make([]byte, len(rrbytes)*3) - off, err = PackRR(rr2, buf, 0, nil, false) - if err != nil { - t.Errorf("error packing parsed rr: %v", err) - t.Errorf("unpacked Struct: %v", rr) - t.Errorf(" string: %v", rrString) - t.Errorf(" parsed Struct: %v", rr2) - return false - } - buf = buf[:off] - if !bytes.Equal(buf, rrbytes) { - t.Errorf("parsed packed bytes don't match original bytes") - t.Errorf(" source bytes: %v", rrbytes) - t.Errorf("unpacked struct: %v", rr) - t.Errorf(" string: %v", rrString) - t.Errorf(" parsed struct: %v", rr2) - t.Errorf(" repacked bytes: %v", buf) - return false - } - return true - } - c := &quick.Config{MaxCountScale: 10} - if err := quick.Check(f, c); err != nil { - t.Error(err) - } -} - -func TestParseDirectiveMisc(t *testing.T) { - tests := map[string]string{ - "$ORIGIN miek.nl.\na IN NS b": "a.miek.nl.\t3600\tIN\tNS\tb.miek.nl.", - "$TTL 2H\nmiek.nl. IN NS b.": "miek.nl.\t7200\tIN\tNS\tb.", - "miek.nl. 1D IN NS b.": "miek.nl.\t86400\tIN\tNS\tb.", - `name. IN SOA a6.nstld.com. hostmaster.nic.name. ( - 203362132 ; serial - 5m ; refresh (5 minutes) - 5m ; retry (5 minutes) - 2w ; expire (2 weeks) - 300 ; minimum (5 minutes) -)`: "name.\t3600\tIN\tSOA\ta6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300", - ". 3600000 IN NS ONE.MY-ROOTS.NET.": ".\t3600000\tIN\tNS\tONE.MY-ROOTS.NET.", - "ONE.MY-ROOTS.NET. 3600000 IN A 192.168.1.1": "ONE.MY-ROOTS.NET.\t3600000\tIN\tA\t192.168.1.1", - } - for i, o := range tests { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestNSEC(t *testing.T) { - nsectests := map[string]string{ - "nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F", - "p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM", - "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC", - "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534", - "localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSec Type65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534", - } - for i, o := range nsectests { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestParseLOC(t *testing.T) { - lt := map[string]string{ - "SW1A2AA.find.me.uk. LOC 51 30 12.748 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 30 12.748 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m", - "SW1A2AA.find.me.uk. LOC 51 0 0.0 N 00 07 39.611 W 0.00m 0.00m 0.00m 0.00m": "SW1A2AA.find.me.uk.\t3600\tIN\tLOC\t51 00 0.000 N 00 07 39.611 W 0m 0.00m 0.00m 0.00m", - } - for i, o := range lt { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestParseDS(t *testing.T) { - dt := map[string]string{ - "example.net. 3600 IN DS 40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F": "example.net.\t3600\tIN\tDS\t40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B2071398F", - } - for i, o := range dt { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestQuotes(t *testing.T) { - tests := map[string]string{ - `t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"", - `t.example.com. IN TXT "a - bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\n bc\"", - `t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"", - `t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"", - `t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"", - `t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"", - `t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"", - `t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"", - `t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa \"", - `t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa aaa\"", - `t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa aaa\"", - `t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"", - "cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.", - "cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.", - "cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.", - "cid.urn.arpa. NAPTR 100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 10 \"\" \"\" \"/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\" .", - } - for i, o := range tests { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestParseClass(t *testing.T) { - tests := map[string]string{ - "t.example.com. IN A 127.0.0.1": "t.example.com. 3600 IN A 127.0.0.1", - "t.example.com. CS A 127.0.0.1": "t.example.com. 3600 CS A 127.0.0.1", - "t.example.com. CH A 127.0.0.1": "t.example.com. 3600 CH A 127.0.0.1", - // ClassANY can not occur in zone files - // "t.example.com. ANY A 127.0.0.1": "t.example.com. 3600 ANY A 127.0.0.1", - "t.example.com. NONE A 127.0.0.1": "t.example.com. 3600 NONE A 127.0.0.1", - } - for i, o := range tests { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestBrace(t *testing.T) { - tests := map[string]string{ - "(miek.nl.) 3600 IN A 127.0.1.1": "miek.nl.\t3600\tIN\tA\t127.0.1.1", - "miek.nl. (3600) IN MX (10) elektron.atoom.net.": "miek.nl.\t3600\tIN\tMX\t10 elektron.atoom.net.", - `miek.nl. IN ( - 3600 A 127.0.0.1)`: "miek.nl.\t3600\tIN\tA\t127.0.0.1", - "(miek.nl.) (A) (127.0.2.1)": "miek.nl.\t3600\tIN\tA\t127.0.2.1", - "miek.nl A 127.0.3.1": "miek.nl.\t3600\tIN\tA\t127.0.3.1", - "_ssh._tcp.local. 60 IN (PTR) stora._ssh._tcp.local.": "_ssh._tcp.local.\t60\tIN\tPTR\tstora._ssh._tcp.local.", - "miek.nl. NS ns.miek.nl": "miek.nl.\t3600\tIN\tNS\tns.miek.nl.", - `(miek.nl.) ( - (IN) - (AAAA) - (::1) )`: "miek.nl.\t3600\tIN\tAAAA\t::1", - `(miek.nl.) ( - (IN) - (AAAA) - (::1))`: "miek.nl.\t3600\tIN\tAAAA\t::1", - "miek.nl. IN AAAA ::2": "miek.nl.\t3600\tIN\tAAAA\t::2", - `((m)(i)ek.(n)l.) (SOA) (soa.) (soa.) ( - 2009032802 ; serial - 21600 ; refresh (6 hours) - 7(2)00 ; retry (2 hours) - 604()800 ; expire (1 week) - 3600 ; minimum (1 hour) - )`: "miek.nl.\t3600\tIN\tSOA\tsoa. soa. 2009032802 21600 7200 604800 3600", - "miek\\.nl. IN A 127.0.0.10": "miek\\.nl.\t3600\tIN\tA\t127.0.0.10", - "miek.nl. IN A 127.0.0.11": "miek.nl.\t3600\tIN\tA\t127.0.0.11", - "miek.nl. A 127.0.0.12": "miek.nl.\t3600\tIN\tA\t127.0.0.12", - `miek.nl. 86400 IN SOA elektron.atoom.net. miekg.atoom.net. ( - 2009032802 ; serial - 21600 ; refresh (6 hours) - 7200 ; retry (2 hours) - 604800 ; expire (1 week) - 3600 ; minimum (1 hour) - )`: "miek.nl.\t86400\tIN\tSOA\telektron.atoom.net. miekg.atoom.net. 2009032802 21600 7200 604800 3600", - } - for i, o := range tests { - rr, err := NewRR(i) - if err != nil { - t.Errorf("failed to parse RR: %v\n\t%s", err, i) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestParseFailure(t *testing.T) { - tests := []string{"miek.nl. IN A 327.0.0.1", - "miek.nl. IN AAAA ::x", - "miek.nl. IN MX a0 miek.nl.", - "miek.nl aap IN MX mx.miek.nl.", - "miek.nl 200 IN mxx 10 mx.miek.nl.", - "miek.nl. inn MX 10 mx.miek.nl.", - // "miek.nl. IN CNAME ", // actually valid nowadays, zero size rdata - "miek.nl. IN CNAME ..", - "miek.nl. PA MX 10 miek.nl.", - "miek.nl. ) IN MX 10 miek.nl.", - } - - for _, s := range tests { - _, err := NewRR(s) - if err == nil { - t.Errorf("should have triggered an error: \"%s\"", s) - } - } -} - -func TestZoneParsing(t *testing.T) { - // parse_test.db - db := ` -a.example.com. IN A 127.0.0.1 -8db7._openpgpkey.example.com. IN OPENPGPKEY mQCNAzIG -$ORIGIN a.example.com. -test IN A 127.0.0.1 -$ORIGIN b.example.com. -test IN CNAME test.a.example.com. -` - start := time.Now().UnixNano() - to := ParseZone(strings.NewReader(db), "", "parse_test.db") - var i int - for x := range to { - i++ - if x.Error != nil { - t.Error(x.Error) - continue - } - t.Log(x.RR) - } - delta := time.Now().UnixNano() - start - t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9)) -} - -func ExampleZone() { - zone := `$ORIGIN . -$TTL 3600 ; 1 hour -name IN SOA a6.nstld.com. hostmaster.nic.name. ( - 203362132 ; serial - 300 ; refresh (5 minutes) - 300 ; retry (5 minutes) - 1209600 ; expire (2 weeks) - 300 ; minimum (5 minutes) - ) -$TTL 10800 ; 3 hours -name. 10800 IN NS name. - IN NS g6.nstld.com. - 7200 NS h6.nstld.com. - 3600 IN NS j6.nstld.com. - IN 3600 NS k6.nstld.com. - NS l6.nstld.com. - NS a6.nstld.com. - NS c6.nstld.com. - NS d6.nstld.com. - NS f6.nstld.com. - NS m6.nstld.com. -( - NS m7.nstld.com. -) -$ORIGIN name. -0-0onlus NS ns7.ehiweb.it. - NS ns8.ehiweb.it. -0-g MX 10 mx01.nic - MX 10 mx02.nic - MX 10 mx03.nic - MX 10 mx04.nic -$ORIGIN 0-g.name -moutamassey NS ns01.yahoodomains.jp. - NS ns02.yahoodomains.jp. -` - to := ParseZone(strings.NewReader(zone), "", "testzone") - for x := range to { - fmt.Println(x.RR) - } - // Output: - // name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300 - // name. 10800 IN NS name. - // name. 10800 IN NS g6.nstld.com. - // name. 7200 IN NS h6.nstld.com. - // name. 3600 IN NS j6.nstld.com. - // name. 3600 IN NS k6.nstld.com. - // name. 10800 IN NS l6.nstld.com. - // name. 10800 IN NS a6.nstld.com. - // name. 10800 IN NS c6.nstld.com. - // name. 10800 IN NS d6.nstld.com. - // name. 10800 IN NS f6.nstld.com. - // name. 10800 IN NS m6.nstld.com. - // name. 10800 IN NS m7.nstld.com. - // 0-0onlus.name. 10800 IN NS ns7.ehiweb.it. - // 0-0onlus.name. 10800 IN NS ns8.ehiweb.it. - // 0-g.name. 10800 IN MX 10 mx01.nic.name. - // 0-g.name. 10800 IN MX 10 mx02.nic.name. - // 0-g.name. 10800 IN MX 10 mx03.nic.name. - // 0-g.name. 10800 IN MX 10 mx04.nic.name. - // moutamassey.0-g.name.name. 10800 IN NS ns01.yahoodomains.jp. - // moutamassey.0-g.name.name. 10800 IN NS ns02.yahoodomains.jp. -} - -func ExampleHIP() { - h := `www.example.com IN HIP ( 2 200100107B1A74DF365639CC39F1D578 - AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p -9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ -b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D - rvs.example.com. )` - if hip, err := NewRR(h); err == nil { - fmt.Println(hip.String()) - } - // Output: - // www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. -} - -func TestHIP(t *testing.T) { - h := `www.example.com. IN HIP ( 2 200100107B1A74DF365639CC39F1D578 - AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p -9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ -b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D - rvs1.example.com. - rvs2.example.com. )` - rr, err := NewRR(h) - if err != nil { - t.Fatalf("failed to parse RR: %v", err) - } - t.Logf("RR: %s", rr) - msg := new(Msg) - msg.Answer = []RR{rr, rr} - bytes, err := msg.Pack() - if err != nil { - t.Fatalf("failed to pack msg: %v", err) - } - if err := msg.Unpack(bytes); err != nil { - t.Fatalf("failed to unpack msg: %v", err) - } - if len(msg.Answer) != 2 { - t.Fatalf("2 answers expected: %v", msg) - } - for i, rr := range msg.Answer { - rr := rr.(*HIP) - t.Logf("RR: %s", rr) - if l := len(rr.RendezvousServers); l != 2 { - t.Fatalf("2 servers expected, only %d in record %d:\n%v", l, i, msg) - } - for j, s := range []string{"rvs1.example.com.", "rvs2.example.com."} { - if rr.RendezvousServers[j] != s { - t.Fatalf("expected server %d of record %d to be %s:\n%v", j, i, s, msg) - } - } - } -} - -func ExampleSOA() { - s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100" - if soa, err := NewRR(s); err == nil { - fmt.Println(soa.String()) - } - // Output: - // example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100 -} - -func TestLineNumberError(t *testing.T) { - s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100" - if _, err := NewRR(s); err != nil { - if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" { - t.Error("not expecting this error: ", err) - } - } -} - -// Test with no known RR on the line -func TestLineNumberError2(t *testing.T) { - tests := map[string]string{ - "example.com. 1000 SO master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100": "dns: expecting RR type or class, not this...: \"SO\" at line: 1:21", - "example.com 1000 IN TALINK a.example.com. b..example.com.": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:57", - "example.com 1000 IN TALINK ( a.example.com. b..example.com. )": "dns: bad TALINK NextName: \"b..example.com.\" at line: 1:60", - `example.com 1000 IN TALINK ( a.example.com. - bb..example.com. )`: "dns: bad TALINK NextName: \"bb..example.com.\" at line: 2:18", - // This is a bug, it should report an error on line 1, but the new is already processed. - `example.com 1000 IN TALINK ( a.example.com. b...example.com. - )`: "dns: bad TALINK NextName: \"b...example.com.\" at line: 2:1"} - - for in, errStr := range tests { - _, err := NewRR(in) - if err == nil { - t.Error("err is nil") - } else { - if err.Error() != errStr { - t.Errorf("%s: error should be %s is %v", in, errStr, err) - } - } - } -} - -// Test if the calculations are correct -func TestRfc1982(t *testing.T) { - // If the current time and the timestamp are more than 68 years apart - // it means the date has wrapped. 0 is 1970 - - // fall in the current 68 year span - strtests := []string{"20120525134203", "19700101000000", "20380119031408"} - for _, v := range strtests { - if x, _ := StringToTime(v); v != TimeToString(x) { - t.Errorf("1982 arithmetic string failure %s (%s:%d)", v, TimeToString(x), x) - } - } - - inttests := map[uint32]string{0: "19700101000000", - 1 << 31: "20380119031408", - 1<<32 - 1: "21060207062815", - } - for i, v := range inttests { - if TimeToString(i) != v { - t.Errorf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToString(i)) - } - } - - // Future tests, these dates get parsed to a date within the current 136 year span - future := map[string]string{"22680119031408": "20631123173144", - "19010101121212": "20370206184028", - "19210101121212": "20570206184028", - "19500101121212": "20860206184028", - "19700101000000": "19700101000000", - "19690101000000": "21050207062816", - "29210101121212": "21040522212236", - } - for from, to := range future { - x, _ := StringToTime(from) - y := TimeToString(x) - if y != to { - t.Errorf("1982 arithmetic future failure %s:%s (%s)", from, to, y) - } - } -} - -func TestEmpty(t *testing.T) { - for _ = range ParseZone(strings.NewReader(""), "", "") { - t.Errorf("should be empty") - } -} - -func TestLowercaseTokens(t *testing.T) { - var testrecords = []string{ - "example.org. 300 IN a 1.2.3.4", - "example.org. 300 in A 1.2.3.4", - "example.org. 300 in a 1.2.3.4", - "example.org. 300 a 1.2.3.4", - "example.org. 300 A 1.2.3.4", - "example.org. IN a 1.2.3.4", - "example.org. in A 1.2.3.4", - "example.org. in a 1.2.3.4", - "example.org. a 1.2.3.4", - "example.org. A 1.2.3.4", - "example.org. a 1.2.3.4", - "$ORIGIN example.org.\n a 1.2.3.4", - "$Origin example.org.\n a 1.2.3.4", - "$origin example.org.\n a 1.2.3.4", - "example.org. Class1 Type1 1.2.3.4", - } - for _, testrr := range testrecords { - _, err := NewRR(testrr) - if err != nil { - t.Errorf("failed to parse %#v, got %v", testrr, err) - } - } -} - -func ExampleGenerate() { - // From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761 - zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0" - to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "") - for x := range to { - if x.Error == nil { - fmt.Println(x.RR.String()) - } - } - // Output: - // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER1.EXAMPLE. - // 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER2.EXAMPLE. - // 1.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 1.0.0.0.192.IN-ADDR.ARPA. - // 2.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 2.0.0.0.192.IN-ADDR.ARPA. - // 3.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 3.0.0.0.192.IN-ADDR.ARPA. - // 4.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 4.0.0.0.192.IN-ADDR.ARPA. - // 5.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 5.0.0.0.192.IN-ADDR.ARPA. - // 6.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 6.0.0.0.192.IN-ADDR.ARPA. - // 7.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 7.0.0.0.192.IN-ADDR.ARPA. - // 8.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 8.0.0.0.192.IN-ADDR.ARPA. -} - -func TestSRVPacking(t *testing.T) { - msg := Msg{} - - things := []string{"1.2.3.4:8484", - "45.45.45.45:8484", - "84.84.84.84:8484", - } - - for i, n := range things { - h, p, err := net.SplitHostPort(n) - if err != nil { - continue - } - port := 8484 - tmp, err := strconv.Atoi(p) - if err == nil { - port = tmp - } - - rr := &SRV{ - Hdr: RR_Header{Name: "somename.", - Rrtype: TypeSRV, - Class: ClassINET, - Ttl: 5}, - Priority: uint16(i), - Weight: 5, - Port: uint16(port), - Target: h + ".", - } - - msg.Answer = append(msg.Answer, rr) - } - - _, err := msg.Pack() - if err != nil { - t.Fatalf("couldn't pack %v: %v", msg, err) - } -} - -func TestParseBackslash(t *testing.T) { - if r, err := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); err != nil { - t.Errorf("could not create RR with \\000 in it") - } else { - t.Logf("parsed %s", r.String()) - } - if r, err := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); err != nil { - t.Errorf("could not create RR with \\000 in it") - } else { - t.Logf("parsed %s", r.String()) - } - if r, err := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); err != nil { - t.Errorf("could not create RR with \\ and \\@ in it") - } else { - t.Logf("parsed %s", r.String()) - } -} - -func TestILNP(t *testing.T) { - tests := []string{ - "host1.example.com.\t3600\tIN\tNID\t10 0014:4fff:ff20:ee64", - "host1.example.com.\t3600\tIN\tNID\t20 0015:5fff:ff21:ee65", - "host2.example.com.\t3600\tIN\tNID\t10 0016:6fff:ff22:ee66", - "host1.example.com.\t3600\tIN\tL32\t10 10.1.2.0", - "host1.example.com.\t3600\tIN\tL32\t20 10.1.4.0", - "host2.example.com.\t3600\tIN\tL32\t10 10.1.8.0", - "host1.example.com.\t3600\tIN\tL64\t10 2001:0DB8:1140:1000", - "host1.example.com.\t3600\tIN\tL64\t20 2001:0DB8:2140:2000", - "host2.example.com.\t3600\tIN\tL64\t10 2001:0DB8:4140:4000", - "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet1.example.com.", - "host1.example.com.\t3600\tIN\tLP\t10 l64-subnet2.example.com.", - "host1.example.com.\t3600\tIN\tLP\t20 l32-subnet1.example.com.", - } - for _, t1 := range tests { - r, err := NewRR(t1) - if err != nil { - t.Fatalf("an error occurred: %v", err) - } else { - if t1 != r.String() { - t.Fatalf("strings should be equal %s %s", t1, r.String()) - } - } - } -} - -func TestNsapGposEidNimloc(t *testing.T) { - dt := map[string]string{ - "foo.bar.com. IN NSAP 21 47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t21 47000580ffff000000321099991111222233334444", - "host.school.de IN NSAP 17 39276f3100111100002222333344449876": "host.school.de.\t3600\tIN\tNSAP\t17 39276f3100111100002222333344449876", - "444433332222111199990123000000ff. NSAP-PTR foo.bar.com.": "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.", - "lillee. IN GPOS -32.6882 116.8652 10.0": "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0", - "hinault. IN GPOS -22.6882 116.8652 250.0": "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0", - "VENERA. IN NIMLOC 75234159EAC457800920": "VENERA.\t3600\tIN\tNIMLOC\t75234159EAC457800920", - "VAXA. IN EID 3141592653589793": "VAXA.\t3600\tIN\tEID\t3141592653589793", - } - for i, o := range dt { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestPX(t *testing.T) { - dt := map[string]string{ - "*.net2.it. IN PX 10 net2.it. PRMD-net2.ADMD-p400.C-it.": "*.net2.it.\t3600\tIN\tPX\t10 net2.it. PRMD-net2.ADMD-p400.C-it.", - "ab.net2.it. IN PX 10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.": "ab.net2.it.\t3600\tIN\tPX\t10 ab.net2.it. O-ab.PRMD-net2.ADMDb.C-it.", - } - for i, o := range dt { - rr, err := NewRR(i) - if err != nil { - t.Error("failed to parse RR: ", err) - continue - } - if rr.String() != o { - t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) - } else { - t.Logf("RR is OK: `%s'", rr.String()) - } - } -} - -func TestComment(t *testing.T) { - // Comments we must see - comments := map[string]bool{"; this is comment 1": true, - "; this is comment 4": true, "; this is comment 6": true, - "; this is comment 7": true, "; this is comment 8": true} - zone := ` -foo. IN A 10.0.0.1 ; this is comment 1 -foo. IN A ( - 10.0.0.2 ; this is comment2 -) -; this is comment3 -foo. IN A 10.0.0.3 -foo. IN A ( 10.0.0.4 ); this is comment 4 - -foo. IN A 10.0.0.5 -; this is comment5 - -foo. IN A 10.0.0.6 - -foo. IN DNSKEY 256 3 5 AwEAAb+8l ; this is comment 6 -foo. IN NSEC miek.nl. TXT RRSIG NSEC; this is comment 7 -foo. IN TXT "THIS IS TEXT MAN"; this is comment 8 -` - for x := range ParseZone(strings.NewReader(zone), ".", "") { - if x.Error == nil { - if x.Comment != "" { - if _, ok := comments[x.Comment]; !ok { - t.Errorf("wrong comment %s", x.Comment) - } - } - } - } -} - -func TestEUIxx(t *testing.T) { - tests := map[string]string{ - "host.example. IN EUI48 00-00-5e-90-01-2a": "host.example.\t3600\tIN\tEUI48\t00-00-5e-90-01-2a", - "host.example. IN EUI64 00-00-5e-ef-00-00-00-2a": "host.example.\t3600\tIN\tEUI64\t00-00-5e-ef-00-00-00-2a", - } - for i, o := range tests { - r, err := NewRR(i) - if err != nil { - t.Errorf("failed to parse %s: %v", i, err) - } - if r.String() != o { - t.Errorf("want %s, got %s", o, r.String()) - } - } -} - -func TestUserRR(t *testing.T) { - tests := map[string]string{ - "host.example. IN UID 1234": "host.example.\t3600\tIN\tUID\t1234", - "host.example. IN GID 1234556": "host.example.\t3600\tIN\tGID\t1234556", - "host.example. IN UINFO \"Miek Gieben\"": "host.example.\t3600\tIN\tUINFO\t\"Miek Gieben\"", - } - for i, o := range tests { - r, err := NewRR(i) - if err != nil { - t.Errorf("failed to parse %s: %v", i, err) - } - if r.String() != o { - t.Errorf("want %s, got %s", o, r.String()) - } - } -} - -func TestTXT(t *testing.T) { - // Test single entry TXT record - rr, err := NewRR(`_raop._tcp.local. 60 IN TXT "single value"`) - if err != nil { - t.Error("failed to parse single value TXT record", err) - } else if rr, ok := rr.(*TXT); !ok { - t.Error("wrong type, record should be of type TXT") - } else { - if len(rr.Txt) != 1 { - t.Error("bad size of TXT value:", len(rr.Txt)) - } else if rr.Txt[0] != "single value" { - t.Error("bad single value") - } - if rr.String() != `_raop._tcp.local. 60 IN TXT "single value"` { - t.Error("bad representation of TXT record:", rr.String()) - } - if rr.len() != 28+1+12 { - t.Error("bad size of serialized record:", rr.len()) - } - } - - // Test multi entries TXT record - rr, err = NewRR(`_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"`) - if err != nil { - t.Error("failed to parse multi-values TXT record", err) - } else if rr, ok := rr.(*TXT); !ok { - t.Error("wrong type, record should be of type TXT") - } else { - if len(rr.Txt) != 4 { - t.Error("bad size of TXT multi-value:", len(rr.Txt)) - } else if rr.Txt[0] != "a=1" || rr.Txt[1] != "b=2" || rr.Txt[2] != "c=3" || rr.Txt[3] != "d=4" { - t.Error("bad values in TXT records") - } - if rr.String() != `_raop._tcp.local. 60 IN TXT "a=1" "b=2" "c=3" "d=4"` { - t.Error("bad representation of TXT multi value record:", rr.String()) - } - if rr.len() != 28+1+3+1+3+1+3+1+3 { - t.Error("bad size of serialized multi value record:", rr.len()) - } - } - - // Test empty-string in TXT record - rr, err = NewRR(`_raop._tcp.local. 60 IN TXT ""`) - if err != nil { - t.Error("failed to parse empty-string TXT record", err) - } else if rr, ok := rr.(*TXT); !ok { - t.Error("wrong type, record should be of type TXT") - } else { - if len(rr.Txt) != 1 { - t.Error("bad size of TXT empty-string value:", len(rr.Txt)) - } else if rr.Txt[0] != "" { - t.Error("bad value for empty-string TXT record") - } - if rr.String() != `_raop._tcp.local. 60 IN TXT ""` { - t.Error("bad representation of empty-string TXT record:", rr.String()) - } - if rr.len() != 28+1 { - t.Error("bad size of serialized record:", rr.len()) - } - } - - // Test TXT record with chunk larger than 255 bytes, they should be split up, by the parser - s := "" - for i := 0; i < 255; i++ { - s += "a" - } - s += "b" - rr, err = NewRR(`test.local. 60 IN TXT "` + s + `"`) - if err != nil { - t.Error("failed to parse empty-string TXT record", err) - } - if rr.(*TXT).Txt[1] != "b" { - t.Errorf("Txt should have two chunk, last one my be 'b', but is %s", rr.(*TXT).Txt[1]) - } - t.Log(rr.String()) -} - -func TestTypeXXXX(t *testing.T) { - _, err := NewRR("example.com IN TYPE1234 \\# 4 aabbccdd") - if err != nil { - t.Errorf("failed to parse TYPE1234 RR: %v", err) - } - _, err = NewRR("example.com IN TYPE655341 \\# 8 aabbccddaabbccdd") - if err == nil { - t.Errorf("this should not work, for TYPE655341") - } - _, err = NewRR("example.com IN TYPE1 \\# 4 0a000001") - if err == nil { - t.Errorf("this should not work") - } -} - -func TestPTR(t *testing.T) { - _, err := NewRR("144.2.0.192.in-addr.arpa. 900 IN PTR ilouse03146p0\\(.example.com.") - if err != nil { - t.Error("failed to parse ", err) - } -} - -func TestDigit(t *testing.T) { - tests := map[string]byte{ - "miek\\000.nl. 100 IN TXT \"A\"": 0, - "miek\\001.nl. 100 IN TXT \"A\"": 1, - "miek\\254.nl. 100 IN TXT \"A\"": 254, - "miek\\255.nl. 100 IN TXT \"A\"": 255, - "miek\\256.nl. 100 IN TXT \"A\"": 0, - "miek\\257.nl. 100 IN TXT \"A\"": 1, - "miek\\004.nl. 100 IN TXT \"A\"": 4, - } - for s, i := range tests { - r, err := NewRR(s) - buf := make([]byte, 40) - if err != nil { - t.Fatalf("failed to parse %v", err) - } - PackRR(r, buf, 0, nil, false) - t.Log(buf) - if buf[5] != i { - t.Fatalf("5 pos must be %d, is %d", i, buf[5]) - } - r1, _, _ := UnpackRR(buf, 0) - if r1.Header().Ttl != 100 { - t.Fatalf("TTL should %d, is %d", 100, r1.Header().Ttl) - } - } -} - -func TestParseRRSIGTimestamp(t *testing.T) { - tests := map[string]bool{ - `miek.nl. IN RRSIG SOA 8 2 43200 20140210031301 20140111031301 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true, - `miek.nl. IN RRSIG SOA 8 2 43200 315565800 4102477800 12051 miek.nl. MVZUyrYwq0iZhMFDDnVXD2BvuNiUJjSYlJAgzyAE6CF875BMvvZa+Sb0 RlSCL7WODQSQHhCx/fegHhVVF+Iz8N8kOLrmXD1+jO3Bm6Prl5UhcsPx WTBsg/kmxbp8sR1kvH4oZJtVfakG3iDerrxNaf0sQwhZzyfJQAqpC7pcBoc=`: true, - } - for r := range tests { - _, err := NewRR(r) - if err != nil { - t.Error(err) - } - } -} - -func TestTxtEqual(t *testing.T) { - rr1 := new(TXT) - rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} - rr1.Txt = []string{"a\"a", "\"", "b"} - rr2, _ := NewRR(rr1.String()) - if rr1.String() != rr2.String() { - // This is not an error, but keep this test. - t.Errorf("these two TXT records should match:\n%s\n%s", rr1.String(), rr2.String()) - } - t.Logf("%s\n%s", rr1.String(), rr2.String()) -} - -func TestTxtLong(t *testing.T) { - rr1 := new(TXT) - rr1.Hdr = RR_Header{Name: ".", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0} - // Make a long txt record, this breaks when sending the packet, - // but not earlier. - rr1.Txt = []string{"start-"} - for i := 0; i < 200; i++ { - rr1.Txt[0] += "start-" - } - str := rr1.String() - if len(str) < len(rr1.Txt[0]) { - t.Error("string conversion should work") - } -} - -// Basically, don't crash. -func TestMalformedPackets(t *testing.T) { - var packets = []string{ - "0021641c0000000100000000000078787878787878787878787303636f6d0000100001", - } - - // com = 63 6f 6d - for _, packet := range packets { - data, _ := hex.DecodeString(packet) - // for _, v := range data { - // t.Log(v) - // } - var msg Msg - msg.Unpack(data) - // println(msg.String()) - } -} - -type algorithm struct { - name uint8 - bits int -} - -func TestNewPrivateKey(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - algorithms := []algorithm{ - algorithm{ECDSAP256SHA256, 256}, - algorithm{ECDSAP384SHA384, 384}, - algorithm{RSASHA1, 1024}, - algorithm{RSASHA256, 2048}, - algorithm{DSA, 1024}, - } - - for _, algo := range algorithms { - key := new(DNSKEY) - key.Hdr.Rrtype = TypeDNSKEY - key.Hdr.Name = "miek.nl." - key.Hdr.Class = ClassINET - key.Hdr.Ttl = 14400 - key.Flags = 256 - key.Protocol = 3 - key.Algorithm = algo.name - privkey, err := key.Generate(algo.bits) - if err != nil { - t.Fatal(err) - } - - newPrivKey, err := key.NewPrivateKey(key.PrivateKeyString(privkey)) - if err != nil { - t.Error(key.String()) - t.Error(key.PrivateKeyString(privkey)) - t.Fatal(err) - } - - switch newPrivKey := newPrivKey.(type) { - case *RSAPrivateKey: - (*rsa.PrivateKey)(newPrivKey).Precompute() - } - - if !reflect.DeepEqual(privkey, newPrivKey) { - t.Errorf("[%v] Private keys differ:\n%#v\n%#v", AlgorithmToString[algo.name], privkey, newPrivKey) - } - } -} - -// special input test -func TestNewRRSpecial(t *testing.T) { - var ( - rr RR - err error - expect string - ) - - rr, err = NewRR("; comment") - expect = "" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr != nil { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } - - rr, err = NewRR("") - expect = "" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr != nil { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } - - rr, err = NewRR("$ORIGIN foo.") - expect = "" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr != nil { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } - - rr, err = NewRR(" ") - expect = "" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr != nil { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } - - rr, err = NewRR("\n") - expect = "" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr != nil { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } - - rr, err = NewRR("foo. A 1.1.1.1\nbar. A 2.2.2.2") - expect = "foo.\t3600\tIN\tA\t1.1.1.1" - if err != nil { - t.Errorf("unexpected err: %v", err) - } - if rr == nil || rr.String() != expect { - t.Errorf("unexpected result: [%s] != [%s]", rr, expect) - } -} - -func TestPrintfVerbsRdata(t *testing.T) { - x, _ := NewRR("www.miek.nl. IN MX 20 mx.miek.nl.") - if Field(x, 1) != "20" { - t.Errorf("should be 20") - } - if Field(x, 2) != "mx.miek.nl." { - t.Errorf("should be mx.miek.nl.") - } - - x, _ = NewRR("www.miek.nl. IN A 127.0.0.1") - if Field(x, 1) != "127.0.0.1" { - t.Errorf("should be 127.0.0.1") - } - - x, _ = NewRR("www.miek.nl. IN AAAA ::1") - if Field(x, 1) != "::1" { - t.Errorf("should be ::1") - } - - x, _ = NewRR("www.miek.nl. IN NSEC a.miek.nl. A NS SOA MX AAAA") - if Field(x, 1) != "a.miek.nl." { - t.Errorf("should be a.miek.nl.") - } - if Field(x, 2) != "A NS SOA MX AAAA" { - t.Errorf("should be A NS SOA MX AAAA") - } - - x, _ = NewRR("www.miek.nl. IN TXT \"first\" \"second\"") - if Field(x, 1) != "first second" { - t.Errorf("should be first second") - } - if Field(x, 0) != "" { - t.Errorf("should be empty") - } -} - -func TestParseIPSECKEY(t *testing.T) { - tests := []string{ - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==", - - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==", - - "38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==", - - "38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "38.1.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==", - - "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )", - "0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0.\t7200\tIN\tIPSECKEY\t10 2 2 2001:db8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==", - } - for i := 0; i < len(tests)-1; i++ { - t1 := tests[i] - e1 := tests[i+1] - r, err := NewRR(t1) - if err != nil { - t.Errorf("failed to parse IPSECKEY %v", err) - continue - } - if r.String() != e1 { - t.Errorf("these two IPSECKEY records should match:\n%s\n%s", r.String(), e1) - } - i++ - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/privaterr.go b/Godeps/_workspace/src/github.com/miekg/dns/privaterr.go deleted file mode 100644 index a3baa0655..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/privaterr.go +++ /dev/null @@ -1,115 +0,0 @@ -package dns - -import ( - "fmt" - "strings" -) - -// PrivateRdata is an interface used for implementing "Private Use" RR types, see -// RFC 6895. This allows one to experiment with new RR types, without requesting an -// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove. -type PrivateRdata interface { - // String returns the text presentaton of the Rdata of the Private RR. - String() string - // Parse parses the Rdata of the private RR. - Parse([]string) error - // Pack is used when packing a private RR into a buffer. - Pack([]byte) (int, error) - // Unpack is used when unpacking a private RR from a buffer. - // TODO(miek): diff. signature than Pack, see edns0.go for instance. - Unpack([]byte) (int, error) - // Copy copies the Rdata. - Copy(PrivateRdata) error - // Len returns the length in octets of the Rdata. - Len() int -} - -// PrivateRR represents an RR that uses a PrivateRdata user-defined type. -// It mocks normal RRs and implements dns.RR interface. -type PrivateRR struct { - Hdr RR_Header - Data PrivateRdata -} - -func mkPrivateRR(rrtype uint16) *PrivateRR { - // Panics if RR is not an instance of PrivateRR. - rrfunc, ok := typeToRR[rrtype] - if !ok { - panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype)) - } - - anyrr := rrfunc() - switch rr := anyrr.(type) { - case *PrivateRR: - return rr - } - panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr)) -} - -func (r *PrivateRR) Header() *RR_Header { return &r.Hdr } -func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() } - -// Private len and copy parts to satisfy RR interface. -func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() } -func (r *PrivateRR) copy() RR { - // make new RR like this: - rr := mkPrivateRR(r.Hdr.Rrtype) - newh := r.Hdr.copyHeader() - rr.Hdr = *newh - - err := r.Data.Copy(rr.Data) - if err != nil { - panic("dns: got value that could not be used to copy Private rdata") - } - return rr -} - -// PrivateHandle registers a private resource record type. It requires -// string and numeric representation of private RR type and generator function as argument. -func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { - rtypestr = strings.ToUpper(rtypestr) - - typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } - TypeToString[rtype] = rtypestr - StringToType[rtypestr] = rtype - - setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := mkPrivateRR(h.Rrtype) - rr.Hdr = h - - var l lex - text := make([]string, 0, 2) // could be 0..N elements, median is probably 1 - FETCH: - for { - // TODO(miek): we could also be returning _QUOTE, this might or might not - // be an issue (basically parsing TXT becomes hard) - switch l = <-c; l.value { - case zNewline, zEOF: - break FETCH - case zString: - text = append(text, l.token) - } - } - - err := rr.Data.Parse(text) - if err != nil { - return nil, &ParseError{f, err.Error(), l}, "" - } - - return rr, nil, "" - } - - typeToparserFunc[rtype] = parserFunc{setPrivateRR, true} -} - -// PrivateHandleRemove removes defenitions required to support private RR type. -func PrivateHandleRemove(rtype uint16) { - rtypestr, ok := TypeToString[rtype] - if ok { - delete(typeToRR, rtype) - delete(TypeToString, rtype) - delete(typeToparserFunc, rtype) - delete(StringToType, rtypestr) - } - return -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go b/Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go deleted file mode 100644 index 88f40c84e..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package dns_test - -import ( - "strings" - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/miekg/dns" -) - -const TypeISBN uint16 = 0x0F01 - -// A crazy new RR type :) -type ISBN struct { - x string // rdata with 10 or 13 numbers, dashes or spaces allowed -} - -func NewISBN() dns.PrivateRdata { return &ISBN{""} } - -func (rd *ISBN) Len() int { return len([]byte(rd.x)) } -func (rd *ISBN) String() string { return rd.x } - -func (rd *ISBN) Parse(txt []string) error { - rd.x = strings.TrimSpace(strings.Join(txt, " ")) - return nil -} - -func (rd *ISBN) Pack(buf []byte) (int, error) { - b := []byte(rd.x) - n := copy(buf, b) - if n != len(b) { - return n, dns.ErrBuf - } - return n, nil -} - -func (rd *ISBN) Unpack(buf []byte) (int, error) { - rd.x = string(buf) - return len(buf), nil -} - -func (rd *ISBN) Copy(dest dns.PrivateRdata) error { - isbn, ok := dest.(*ISBN) - if !ok { - return dns.ErrRdata - } - isbn.x = rd.x - return nil -} - -var testrecord = strings.Join([]string{"example.org.", "3600", "IN", "ISBN", "12-3 456789-0-123"}, "\t") - -func TestPrivateText(t *testing.T) { - dns.PrivateHandle("ISBN", TypeISBN, NewISBN) - defer dns.PrivateHandleRemove(TypeISBN) - - rr, err := dns.NewRR(testrecord) - if err != nil { - t.Fatal(err) - } - if rr.String() != testrecord { - t.Errorf("record string representation did not match original %#v != %#v", rr.String(), testrecord) - } else { - t.Log(rr.String()) - } -} - -func TestPrivateByteSlice(t *testing.T) { - dns.PrivateHandle("ISBN", TypeISBN, NewISBN) - defer dns.PrivateHandleRemove(TypeISBN) - - rr, err := dns.NewRR(testrecord) - if err != nil { - t.Fatal(err) - } - - buf := make([]byte, 100) - off, err := dns.PackRR(rr, buf, 0, nil, false) - if err != nil { - t.Errorf("got error packing ISBN: %v", err) - } - - custrr := rr.(*dns.PrivateRR) - if ln := custrr.Data.Len() + len(custrr.Header().Name) + 11; ln != off { - t.Errorf("offset is not matching to length of Private RR: %d!=%d", off, ln) - } - - rr1, off1, err := dns.UnpackRR(buf[:off], 0) - if err != nil { - t.Errorf("got error unpacking ISBN: %v", err) - } - - if off1 != off { - t.Errorf("Offset after unpacking differs: %d != %d", off1, off) - } - - if rr1.String() != testrecord { - t.Errorf("Record string representation did not match original %#v != %#v", rr1.String(), testrecord) - } else { - t.Log(rr1.String()) - } -} - -const TypeVERSION uint16 = 0x0F02 - -type VERSION struct { - x string -} - -func NewVersion() dns.PrivateRdata { return &VERSION{""} } - -func (rd *VERSION) String() string { return rd.x } -func (rd *VERSION) Parse(txt []string) error { - rd.x = strings.TrimSpace(strings.Join(txt, " ")) - return nil -} - -func (rd *VERSION) Pack(buf []byte) (int, error) { - b := []byte(rd.x) - n := copy(buf, b) - if n != len(b) { - return n, dns.ErrBuf - } - return n, nil -} - -func (rd *VERSION) Unpack(buf []byte) (int, error) { - rd.x = string(buf) - return len(buf), nil -} - -func (rd *VERSION) Copy(dest dns.PrivateRdata) error { - isbn, ok := dest.(*VERSION) - if !ok { - return dns.ErrRdata - } - isbn.x = rd.x - return nil -} - -func (rd *VERSION) Len() int { - return len([]byte(rd.x)) -} - -var smallzone = `$ORIGIN example.org. -@ SOA sns.dns.icann.org. noc.dns.icann.org. ( - 2014091518 7200 3600 1209600 3600 -) - A 1.2.3.4 -ok ISBN 1231-92110-12 -go VERSION ( - 1.3.1 ; comment -) -www ISBN 1231-92110-16 -* CNAME @ -` - -func TestPrivateZoneParser(t *testing.T) { - dns.PrivateHandle("ISBN", TypeISBN, NewISBN) - dns.PrivateHandle("VERSION", TypeVERSION, NewVersion) - defer dns.PrivateHandleRemove(TypeISBN) - defer dns.PrivateHandleRemove(TypeVERSION) - - r := strings.NewReader(smallzone) - for x := range dns.ParseZone(r, ".", "") { - if err := x.Error; err != nil { - t.Fatal(err) - } - t.Log(x.RR) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go b/Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go deleted file mode 100644 index f138b7761..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go +++ /dev/null @@ -1,95 +0,0 @@ -package dns - -// These raw* functions do not use reflection, they directly set the values -// in the buffer. There are faster than their reflection counterparts. - -// RawSetId sets the message id in buf. -func rawSetId(msg []byte, i uint16) bool { - if len(msg) < 2 { - return false - } - msg[0], msg[1] = packUint16(i) - return true -} - -// rawSetQuestionLen sets the length of the question section. -func rawSetQuestionLen(msg []byte, i uint16) bool { - if len(msg) < 6 { - return false - } - msg[4], msg[5] = packUint16(i) - return true -} - -// rawSetAnswerLen sets the lenght of the answer section. -func rawSetAnswerLen(msg []byte, i uint16) bool { - if len(msg) < 8 { - return false - } - msg[6], msg[7] = packUint16(i) - return true -} - -// rawSetsNsLen sets the lenght of the authority section. -func rawSetNsLen(msg []byte, i uint16) bool { - if len(msg) < 10 { - return false - } - msg[8], msg[9] = packUint16(i) - return true -} - -// rawSetExtraLen sets the lenght of the additional section. -func rawSetExtraLen(msg []byte, i uint16) bool { - if len(msg) < 12 { - return false - } - msg[10], msg[11] = packUint16(i) - return true -} - -// rawSetRdlength sets the rdlength in the header of -// the RR. The offset 'off' must be positioned at the -// start of the header of the RR, 'end' must be the -// end of the RR. -func rawSetRdlength(msg []byte, off, end int) bool { - l := len(msg) -Loop: - for { - if off+1 > l { - return false - } - c := int(msg[off]) - off++ - switch c & 0xC0 { - case 0x00: - if c == 0x00 { - // End of the domainname - break Loop - } - if off+c > l { - return false - } - off += c - - case 0xC0: - // pointer, next byte included, ends domainname - off++ - break Loop - } - } - // The domainname has been seen, we at the start of the fixed part in the header. - // Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length. - off += 2 + 2 + 4 - if off+2 > l { - return false - } - //off+1 is the end of the header, 'end' is the end of the rr - //so 'end' - 'off+2' is the length of the rdata - rdatalen := end - (off + 2) - if rdatalen > 0xFFFF { - return false - } - msg[off], msg[off+1] = packUint16(uint16(rdatalen)) - return true -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/scanner.go b/Godeps/_workspace/src/github.com/miekg/dns/scanner.go deleted file mode 100644 index c29bc2f38..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/scanner.go +++ /dev/null @@ -1,43 +0,0 @@ -package dns - -// Implement a simple scanner, return a byte stream from an io reader. - -import ( - "bufio" - "io" - "text/scanner" -) - -type scan struct { - src *bufio.Reader - position scanner.Position - eof bool // Have we just seen a eof -} - -func scanInit(r io.Reader) *scan { - s := new(scan) - s.src = bufio.NewReader(r) - s.position.Line = 1 - return s -} - -// tokenText returns the next byte from the input -func (s *scan) tokenText() (byte, error) { - c, err := s.src.ReadByte() - if err != nil { - return c, err - } - // delay the newline handling until the next token is delivered, - // fixes off-by-one errors when reporting a parse error. - if s.eof == true { - s.position.Line++ - s.position.Column = 0 - s.eof = false - } - if c == '\n' { - s.eof = true - return c, nil - } - s.position.Column++ - return c, nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/server.go b/Godeps/_workspace/src/github.com/miekg/dns/server.go deleted file mode 100644 index 5e4ec92ba..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/server.go +++ /dev/null @@ -1,630 +0,0 @@ -// DNS server implementation. - -package dns - -import ( - "bytes" - "io" - "net" - "sync" - "time" -) - -// Handler is implemented by any value that implements ServeDNS. -type Handler interface { - ServeDNS(w ResponseWriter, r *Msg) -} - -// A ResponseWriter interface is used by an DNS handler to -// construct an DNS response. -type ResponseWriter interface { - // LocalAddr returns the net.Addr of the server - LocalAddr() net.Addr - // RemoteAddr returns the net.Addr of the client that sent the current request. - RemoteAddr() net.Addr - // WriteMsg writes a reply back to the client. - WriteMsg(*Msg) error - // Write writes a raw buffer back to the client. - Write([]byte) (int, error) - // Close closes the connection. - Close() error - // TsigStatus returns the status of the Tsig. - TsigStatus() error - // TsigTimersOnly sets the tsig timers only boolean. - TsigTimersOnly(bool) - // Hijack lets the caller take over the connection. - // After a call to Hijack(), the DNS package will not do anything with the connection. - Hijack() -} - -type response struct { - hijacked bool // connection has been hijacked by handler - tsigStatus error - tsigTimersOnly bool - tsigRequestMAC string - tsigSecret map[string]string // the tsig secrets - udp *net.UDPConn // i/o connection if UDP was used - tcp *net.TCPConn // i/o connection if TCP was used - udpSession *SessionUDP // oob data to get egress interface right - remoteAddr net.Addr // address of the client -} - -// ServeMux is an DNS request multiplexer. It matches the -// zone name of each incoming request against a list of -// registered patterns add calls the handler for the pattern -// that most closely matches the zone name. ServeMux is DNSSEC aware, meaning -// that queries for the DS record are redirected to the parent zone (if that -// is also registered), otherwise the child gets the query. -// ServeMux is also safe for concurrent access from multiple goroutines. -type ServeMux struct { - z map[string]Handler - m *sync.RWMutex -} - -// NewServeMux allocates and returns a new ServeMux. -func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} } - -// DefaultServeMux is the default ServeMux used by Serve. -var DefaultServeMux = NewServeMux() - -// The HandlerFunc type is an adapter to allow the use of -// ordinary functions as DNS handlers. If f is a function -// with the appropriate signature, HandlerFunc(f) is a -// Handler object that calls f. -type HandlerFunc func(ResponseWriter, *Msg) - -// ServeDNS calls f(w, r). -func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) { - f(w, r) -} - -// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets. -func HandleFailed(w ResponseWriter, r *Msg) { - m := new(Msg) - m.SetRcode(r, RcodeServerFailure) - // does not matter if this write fails - w.WriteMsg(m) -} - -func failedHandler() Handler { return HandlerFunc(HandleFailed) } - -// ListenAndServe Starts a server on addresss and network speficied. Invoke handler -// for incoming queries. -func ListenAndServe(addr string, network string, handler Handler) error { - server := &Server{Addr: addr, Net: network, Handler: handler} - return server.ListenAndServe() -} - -// ActivateAndServe activates a server with a listener from systemd, -// l and p should not both be non-nil. -// If both l and p are not nil only p will be used. -// Invoke handler for incoming queries. -func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error { - server := &Server{Listener: l, PacketConn: p, Handler: handler} - return server.ActivateAndServe() -} - -func (mux *ServeMux) match(q string, t uint16) Handler { - mux.m.RLock() - defer mux.m.RUnlock() - var handler Handler - b := make([]byte, len(q)) // worst case, one label of length q - off := 0 - end := false - for { - l := len(q[off:]) - for i := 0; i < l; i++ { - b[i] = q[off+i] - if b[i] >= 'A' && b[i] <= 'Z' { - b[i] |= ('a' - 'A') - } - } - if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key - if t != TypeDS { - return h - } - // Continue for DS to see if we have a parent too, if so delegeate to the parent - handler = h - } - off, end = NextLabel(q, off) - if end { - break - } - } - // Wildcard match, if we have found nothing try the root zone as a last resort. - if h, ok := mux.z["."]; ok { - return h - } - return handler -} - -// Handle adds a handler to the ServeMux for pattern. -func (mux *ServeMux) Handle(pattern string, handler Handler) { - if pattern == "" { - panic("dns: invalid pattern " + pattern) - } - mux.m.Lock() - mux.z[Fqdn(pattern)] = handler - mux.m.Unlock() -} - -// HandleFunc adds a handler function to the ServeMux for pattern. -func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { - mux.Handle(pattern, HandlerFunc(handler)) -} - -// HandleRemove deregistrars the handler specific for pattern from the ServeMux. -func (mux *ServeMux) HandleRemove(pattern string) { - if pattern == "" { - panic("dns: invalid pattern " + pattern) - } - // don't need a mutex here, because deleting is OK, even if the - // entry is note there. - delete(mux.z, Fqdn(pattern)) -} - -// ServeDNS dispatches the request to the handler whose -// pattern most closely matches the request message. If DefaultServeMux -// is used the correct thing for DS queries is done: a possible parent -// is sought. -// If no handler is found a standard SERVFAIL message is returned -// If the request message does not have exactly one question in the -// question section a SERVFAIL is returned, unlesss Unsafe is true. -func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) { - var h Handler - if len(request.Question) < 1 { // allow more than one question - h = failedHandler() - } else { - if h = mux.match(request.Question[0].Name, request.Question[0].Qtype); h == nil { - h = failedHandler() - } - } - h.ServeDNS(w, request) -} - -// Handle registers the handler with the given pattern -// in the DefaultServeMux. The documentation for -// ServeMux explains how patterns are matched. -func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } - -// HandleRemove deregisters the handle with the given pattern -// in the DefaultServeMux. -func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) } - -// HandleFunc registers the handler function with the given pattern -// in the DefaultServeMux. -func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { - DefaultServeMux.HandleFunc(pattern, handler) -} - -// A Server defines parameters for running an DNS server. -type Server struct { - // Address to listen on, ":dns" if empty. - Addr string - // if "tcp" it will invoke a TCP listener, otherwise an UDP one. - Net string - // TCP Listener to use, this is to aid in systemd's socket activation. - Listener net.Listener - // UDP "Listener" to use, this is to aid in systemd's socket activation. - PacketConn net.PacketConn - // Handler to invoke, dns.DefaultServeMux if nil. - Handler Handler - // Default buffer size to use to read incoming UDP messages. If not set - // it defaults to MinMsgSize (512 B). - UDPSize int - // The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second. - ReadTimeout time.Duration - // The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second. - WriteTimeout time.Duration - // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966). - IdleTimeout func() time.Duration - // Secret(s) for Tsig map[]. - TsigSecret map[string]string - // Unsafe instructs the server to disregard any sanity checks and directly hand the message to - // the handler. It will specfically not check if the query has the QR bit not set. - Unsafe bool - // If NotifyStartedFunc is set is is called, once the server has started listening. - NotifyStartedFunc func() - - // For graceful shutdown. - stopUDP chan bool - stopTCP chan bool - wgUDP sync.WaitGroup - wgTCP sync.WaitGroup - - // make start/shutdown not racy - lock sync.Mutex - started bool -} - -// ListenAndServe starts a nameserver on the configured address in *Server. -func (srv *Server) ListenAndServe() error { - srv.lock.Lock() - if srv.started { - srv.lock.Unlock() - return &Error{err: "server already started"} - } - srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) - srv.started = true - srv.lock.Unlock() - addr := srv.Addr - if addr == "" { - addr = ":domain" - } - if srv.UDPSize == 0 { - srv.UDPSize = MinMsgSize - } - switch srv.Net { - case "tcp", "tcp4", "tcp6": - a, e := net.ResolveTCPAddr(srv.Net, addr) - if e != nil { - return e - } - l, e := net.ListenTCP(srv.Net, a) - if e != nil { - return e - } - srv.Listener = l - return srv.serveTCP(l) - case "udp", "udp4", "udp6": - a, e := net.ResolveUDPAddr(srv.Net, addr) - if e != nil { - return e - } - l, e := net.ListenUDP(srv.Net, a) - if e != nil { - return e - } - if e := setUDPSocketOptions(l); e != nil { - return e - } - srv.PacketConn = l - return srv.serveUDP(l) - } - return &Error{err: "bad network"} -} - -// ActivateAndServe starts a nameserver with the PacketConn or Listener -// configured in *Server. Its main use is to start a server from systemd. -func (srv *Server) ActivateAndServe() error { - srv.lock.Lock() - if srv.started { - srv.lock.Unlock() - return &Error{err: "server already started"} - } - srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) - srv.started = true - srv.lock.Unlock() - if srv.PacketConn != nil { - if srv.UDPSize == 0 { - srv.UDPSize = MinMsgSize - } - if t, ok := srv.PacketConn.(*net.UDPConn); ok { - if e := setUDPSocketOptions(t); e != nil { - return e - } - return srv.serveUDP(t) - } - } - if srv.Listener != nil { - if t, ok := srv.Listener.(*net.TCPListener); ok { - return srv.serveTCP(t) - } - } - return &Error{err: "bad listeners"} -} - -// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and -// ActivateAndServe will return. All in progress queries are completed before the server -// is taken down. If the Shutdown is taking longer than the reading timeout and error -// is returned. -func (srv *Server) Shutdown() error { - srv.lock.Lock() - if !srv.started { - srv.lock.Unlock() - return &Error{err: "server not started"} - } - srv.started = false - srv.lock.Unlock() - net, addr := srv.Net, srv.Addr - switch { - case srv.Listener != nil: - a := srv.Listener.Addr() - net, addr = a.Network(), a.String() - case srv.PacketConn != nil: - a := srv.PacketConn.LocalAddr() - net, addr = a.Network(), a.String() - } - - fin := make(chan bool) - switch net { - case "tcp", "tcp4", "tcp6": - go func() { - srv.stopTCP <- true - srv.wgTCP.Wait() - fin <- true - }() - - case "udp", "udp4", "udp6": - go func() { - srv.stopUDP <- true - srv.wgUDP.Wait() - fin <- true - }() - } - - c := &Client{Net: net} - go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass - - select { - case <-time.After(srv.getReadTimeout()): - return &Error{err: "server shutdown is pending"} - case <-fin: - return nil - } -} - -// getReadTimeout is a helper func to use system timeout if server did not intend to change it. -func (srv *Server) getReadTimeout() time.Duration { - rtimeout := dnsTimeout - if srv.ReadTimeout != 0 { - rtimeout = srv.ReadTimeout - } - return rtimeout -} - -// serveTCP starts a TCP listener for the server. -// Each request is handled in a separate goroutine. -func (srv *Server) serveTCP(l *net.TCPListener) error { - defer l.Close() - - if srv.NotifyStartedFunc != nil { - srv.NotifyStartedFunc() - } - - handler := srv.Handler - if handler == nil { - handler = DefaultServeMux - } - rtimeout := srv.getReadTimeout() - // deadline is not used here - for { - rw, e := l.AcceptTCP() - if e != nil { - continue - } - m, e := srv.readTCP(rw, rtimeout) - select { - case <-srv.stopTCP: - return nil - default: - } - if e != nil { - continue - } - srv.wgTCP.Add(1) - go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw) - } - panic("dns: not reached") -} - -// serveUDP starts a UDP listener for the server. -// Each request is handled in a separate goroutine. -func (srv *Server) serveUDP(l *net.UDPConn) error { - defer l.Close() - - if srv.NotifyStartedFunc != nil { - srv.NotifyStartedFunc() - } - - handler := srv.Handler - if handler == nil { - handler = DefaultServeMux - } - rtimeout := srv.getReadTimeout() - // deadline is not used here - for { - m, s, e := srv.readUDP(l, rtimeout) - select { - case <-srv.stopUDP: - return nil - default: - } - if e != nil { - continue - } - srv.wgUDP.Add(1) - go srv.serve(s.RemoteAddr(), handler, m, l, s, nil) - } - panic("dns: not reached") -} - -// Serve a new connection. -func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) { - w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s} - q := 0 - defer func() { - if u != nil { - srv.wgUDP.Done() - } - if t != nil { - srv.wgTCP.Done() - } - }() -Redo: - req := new(Msg) - err := req.Unpack(m) - if err != nil { // Send a FormatError back - x := new(Msg) - x.SetRcodeFormatError(req) - w.WriteMsg(x) - goto Exit - } - if !srv.Unsafe && req.Response { - goto Exit - } - - w.tsigStatus = nil - if w.tsigSecret != nil { - if t := req.IsTsig(); t != nil { - secret := t.Hdr.Name - if _, ok := w.tsigSecret[secret]; !ok { - w.tsigStatus = ErrKeyAlg - } - w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false) - w.tsigTimersOnly = false - w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC - } - } - h.ServeDNS(w, req) // Writes back to the client - -Exit: - if w.hijacked { - return // client calls Close() - } - if u != nil { // UDP, "close" and return - w.Close() - return - } - idleTimeout := tcpIdleTimeout - if srv.IdleTimeout != nil { - idleTimeout = srv.IdleTimeout() - } - m, e := srv.readTCP(w.tcp, idleTimeout) - if e == nil { - q++ - // TODO(miek): make this number configurable? - if q > 128 { // close socket after this many queries - w.Close() - return - } - goto Redo - } - w.Close() - return -} - -func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) { - conn.SetReadDeadline(time.Now().Add(timeout)) - l := make([]byte, 2) - n, err := conn.Read(l) - if err != nil || n != 2 { - if err != nil { - return nil, err - } - return nil, ErrShortRead - } - length, _ := unpackUint16(l, 0) - if length == 0 { - return nil, ErrShortRead - } - m := make([]byte, int(length)) - n, err = conn.Read(m[:int(length)]) - if err != nil || n == 0 { - if err != nil { - return nil, err - } - return nil, ErrShortRead - } - i := n - for i < int(length) { - j, err := conn.Read(m[i:int(length)]) - if err != nil { - return nil, err - } - i += j - } - n = i - m = m[:n] - return m, nil -} - -func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) { - conn.SetReadDeadline(time.Now().Add(timeout)) - m := make([]byte, srv.UDPSize) - n, s, e := ReadFromSessionUDP(conn, m) - if e != nil || n == 0 { - if e != nil { - return nil, nil, e - } - return nil, nil, ErrShortRead - } - m = m[:n] - return m, s, nil -} - -// WriteMsg implements the ResponseWriter.WriteMsg method. -func (w *response) WriteMsg(m *Msg) (err error) { - var data []byte - if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check) - if t := m.IsTsig(); t != nil { - data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly) - if err != nil { - return err - } - _, err = w.Write(data) - return err - } - } - data, err = m.Pack() - if err != nil { - return err - } - _, err = w.Write(data) - return err -} - -// Write implements the ResponseWriter.Write method. -func (w *response) Write(m []byte) (int, error) { - switch { - case w.udp != nil: - n, err := WriteToSessionUDP(w.udp, m, w.udpSession) - return n, err - case w.tcp != nil: - lm := len(m) - if lm < 2 { - return 0, io.ErrShortBuffer - } - if lm > MaxMsgSize { - return 0, &Error{err: "message too large"} - } - l := make([]byte, 2, 2+lm) - l[0], l[1] = packUint16(uint16(lm)) - m = append(l, m...) - - n, err := io.Copy(w.tcp, bytes.NewReader(m)) - return int(n), err - } - panic("not reached") -} - -// LocalAddr implements the ResponseWriter.LocalAddr method. -func (w *response) LocalAddr() net.Addr { - if w.tcp != nil { - return w.tcp.LocalAddr() - } - return w.udp.LocalAddr() -} - -// RemoteAddr implements the ResponseWriter.RemoteAddr method. -func (w *response) RemoteAddr() net.Addr { return w.remoteAddr } - -// TsigStatus implements the ResponseWriter.TsigStatus method. -func (w *response) TsigStatus() error { return w.tsigStatus } - -// TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method. -func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b } - -// Hijack implements the ResponseWriter.Hijack method. -func (w *response) Hijack() { w.hijacked = true } - -// Close implements the ResponseWriter.Close method -func (w *response) Close() error { - // Can't close the udp conn, as that is actually the listener. - if w.tcp != nil { - e := w.tcp.Close() - w.tcp = nil - return e - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/server_test.go b/Godeps/_workspace/src/github.com/miekg/dns/server_test.go deleted file mode 100644 index c2422b1f7..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/server_test.go +++ /dev/null @@ -1,389 +0,0 @@ -package dns - -import ( - "fmt" - "net" - "runtime" - "sync" - "testing" -) - -func HelloServer(w ResponseWriter, req *Msg) { - m := new(Msg) - m.SetReply(req) - - m.Extra = make([]RR, 1) - m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} - w.WriteMsg(m) -} - -func AnotherHelloServer(w ResponseWriter, req *Msg) { - m := new(Msg) - m.SetReply(req) - - m.Extra = make([]RR, 1) - m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}} - w.WriteMsg(m) -} - -func RunLocalUDPServer(laddr string) (*Server, string, error) { - pc, err := net.ListenPacket("udp", laddr) - if err != nil { - return nil, "", err - } - server := &Server{PacketConn: pc} - - waitLock := sync.Mutex{} - waitLock.Lock() - server.NotifyStartedFunc = waitLock.Unlock - - go func() { - server.ActivateAndServe() - pc.Close() - }() - - waitLock.Lock() - return server, pc.LocalAddr().String(), nil -} - -func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) { - pc, err := net.ListenPacket("udp", laddr) - if err != nil { - return nil, "", err - } - server := &Server{PacketConn: pc, Unsafe: true} - - waitLock := sync.Mutex{} - waitLock.Lock() - server.NotifyStartedFunc = waitLock.Unlock - - go func() { - server.ActivateAndServe() - pc.Close() - }() - - waitLock.Lock() - return server, pc.LocalAddr().String(), nil -} - -func RunLocalTCPServer(laddr string) (*Server, string, error) { - l, err := net.Listen("tcp", laddr) - if err != nil { - return nil, "", err - } - - server := &Server{Listener: l} - - waitLock := sync.Mutex{} - waitLock.Lock() - server.NotifyStartedFunc = waitLock.Unlock - - go func() { - server.ActivateAndServe() - l.Close() - }() - - waitLock.Lock() - return server, l.Addr().String(), nil -} - -func TestServing(t *testing.T) { - HandleFunc("miek.nl.", HelloServer) - HandleFunc("example.com.", AnotherHelloServer) - defer HandleRemove("miek.nl.") - defer HandleRemove("example.com.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - c := new(Client) - m := new(Msg) - m.SetQuestion("miek.nl.", TypeTXT) - r, _, err := c.Exchange(m, addrstr) - if err != nil || len(r.Extra) == 0 { - t.Fatal("failed to exchange miek.nl", err) - } - txt := r.Extra[0].(*TXT).Txt[0] - if txt != "Hello world" { - t.Error("Unexpected result for miek.nl", txt, "!= Hello world") - } - - m.SetQuestion("example.com.", TypeTXT) - r, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Fatal("failed to exchange example.com", err) - } - txt = r.Extra[0].(*TXT).Txt[0] - if txt != "Hello example" { - t.Error("Unexpected result for example.com", txt, "!= Hello example") - } - - // Test Mixes cased as noticed by Ask. - m.SetQuestion("eXaMplE.cOm.", TypeTXT) - r, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Error("failed to exchange eXaMplE.cOm", err) - } - txt = r.Extra[0].(*TXT).Txt[0] - if txt != "Hello example" { - t.Error("Unexpected result for example.com", txt, "!= Hello example") - } -} - -func BenchmarkServe(b *testing.B) { - b.StopTimer() - HandleFunc("miek.nl.", HelloServer) - defer HandleRemove("miek.nl.") - a := runtime.GOMAXPROCS(4) - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - b.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - c := new(Client) - m := new(Msg) - m.SetQuestion("miek.nl", TypeSOA) - - b.StartTimer() - for i := 0; i < b.N; i++ { - c.Exchange(m, addrstr) - } - runtime.GOMAXPROCS(a) -} - -func benchmarkServe6(b *testing.B) { - b.StopTimer() - HandleFunc("miek.nl.", HelloServer) - defer HandleRemove("miek.nl.") - a := runtime.GOMAXPROCS(4) - s, addrstr, err := RunLocalUDPServer("[::1]:0") - if err != nil { - b.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - c := new(Client) - m := new(Msg) - m.SetQuestion("miek.nl", TypeSOA) - - b.StartTimer() - for i := 0; i < b.N; i++ { - c.Exchange(m, addrstr) - } - runtime.GOMAXPROCS(a) -} - -func HelloServerCompress(w ResponseWriter, req *Msg) { - m := new(Msg) - m.SetReply(req) - m.Extra = make([]RR, 1) - m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} - m.Compress = true - w.WriteMsg(m) -} - -func BenchmarkServeCompress(b *testing.B) { - b.StopTimer() - HandleFunc("miek.nl.", HelloServerCompress) - defer HandleRemove("miek.nl.") - a := runtime.GOMAXPROCS(4) - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - b.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - c := new(Client) - m := new(Msg) - m.SetQuestion("miek.nl", TypeSOA) - b.StartTimer() - for i := 0; i < b.N; i++ { - c.Exchange(m, addrstr) - } - runtime.GOMAXPROCS(a) -} - -func TestDotAsCatchAllWildcard(t *testing.T) { - mux := NewServeMux() - mux.Handle(".", HandlerFunc(HelloServer)) - mux.Handle("example.com.", HandlerFunc(AnotherHelloServer)) - - handler := mux.match("www.miek.nl.", TypeTXT) - if handler == nil { - t.Error("wildcard match failed") - } - - handler = mux.match("www.example.com.", TypeTXT) - if handler == nil { - t.Error("example.com match failed") - } - - handler = mux.match("a.www.example.com.", TypeTXT) - if handler == nil { - t.Error("a.www.example.com match failed") - } - - handler = mux.match("boe.", TypeTXT) - if handler == nil { - t.Error("boe. match failed") - } -} - -func TestCaseFolding(t *testing.T) { - mux := NewServeMux() - mux.Handle("_udp.example.com.", HandlerFunc(HelloServer)) - - handler := mux.match("_dns._udp.example.com.", TypeSRV) - if handler == nil { - t.Error("case sensitive characters folded") - } - - handler = mux.match("_DNS._UDP.EXAMPLE.COM.", TypeSRV) - if handler == nil { - t.Error("case insensitive characters not folded") - } -} - -func TestRootServer(t *testing.T) { - mux := NewServeMux() - mux.Handle(".", HandlerFunc(HelloServer)) - - handler := mux.match(".", TypeNS) - if handler == nil { - t.Error("root match failed") - } -} - -type maxRec struct { - max int - sync.RWMutex -} - -var M = new(maxRec) - -func HelloServerLargeResponse(resp ResponseWriter, req *Msg) { - m := new(Msg) - m.SetReply(req) - m.Authoritative = true - m1 := 0 - M.RLock() - m1 = M.max - M.RUnlock() - for i := 0; i < m1; i++ { - aRec := &A{ - Hdr: RR_Header{ - Name: req.Question[0].Name, - Rrtype: TypeA, - Class: ClassINET, - Ttl: 0, - }, - A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i+1)).To4(), - } - m.Answer = append(m.Answer, aRec) - } - resp.WriteMsg(m) -} - -func TestServingLargeResponses(t *testing.T) { - HandleFunc("example.", HelloServerLargeResponse) - defer HandleRemove("example.") - - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - // Create request - m := new(Msg) - m.SetQuestion("web.service.example.", TypeANY) - - c := new(Client) - c.Net = "udp" - M.Lock() - M.max = 2 - M.Unlock() - _, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Errorf("failed to exchange: %v", err) - } - // This must fail - M.Lock() - M.max = 20 - M.Unlock() - _, _, err = c.Exchange(m, addrstr) - if err == nil { - t.Error("failed to fail exchange, this should generate packet error") - } - // But this must work again - c.UDPSize = 7000 - _, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Errorf("failed to exchange: %v", err) - } -} - -func TestServingResponse(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - HandleFunc("miek.nl.", HelloServer) - s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - - c := new(Client) - m := new(Msg) - m.SetQuestion("miek.nl.", TypeTXT) - m.Response = false - _, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Fatal("failed to exchange", err) - } - m.Response = true - _, _, err = c.Exchange(m, addrstr) - if err == nil { - t.Fatal("exchanged response message") - } - - s.Shutdown() - s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - defer s.Shutdown() - - m.Response = true - _, _, err = c.Exchange(m, addrstr) - if err != nil { - t.Fatal("could exchanged response message in Unsafe mode") - } -} - -func TestShutdownTCP(t *testing.T) { - s, _, err := RunLocalTCPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - err = s.Shutdown() - if err != nil { - t.Errorf("Could not shutdown test TCP server, %v", err) - } -} - -func TestShutdownUDP(t *testing.T) { - s, _, err := RunLocalUDPServer("127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to run test server: %v", err) - } - err = s.Shutdown() - if err != nil { - t.Errorf("Could not shutdown test UDP server, %v", err) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/sig0.go b/Godeps/_workspace/src/github.com/miekg/dns/sig0.go deleted file mode 100644 index 55d1a4ed4..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/sig0.go +++ /dev/null @@ -1,221 +0,0 @@ -package dns - -import ( - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/rsa" - "math/big" - "strings" - "time" -) - -// Sign signs a dns.Msg. It fills the signature with the appropriate data. -// The SIG record should have the SignerName, KeyTag, Algorithm, Inception -// and Expiration set. -func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { - if k == nil { - return nil, ErrPrivKey - } - if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { - return nil, ErrKey - } - rr.Header().Rrtype = TypeSIG - rr.Header().Class = ClassANY - rr.Header().Ttl = 0 - rr.Header().Name = "." - rr.OrigTtl = 0 - rr.TypeCovered = 0 - rr.Labels = 0 - - buf := make([]byte, m.Len()+rr.len()) - mbuf, err := m.PackBuffer(buf) - if err != nil { - return nil, err - } - if &buf[0] != &mbuf[0] { - return nil, ErrBuf - } - off, err := PackRR(rr, buf, len(mbuf), nil, false) - if err != nil { - return nil, err - } - buf = buf[:off:cap(buf)] - var hash crypto.Hash - switch rr.Algorithm { - case DSA, RSASHA1: - hash = crypto.SHA1 - case RSASHA256, ECDSAP256SHA256: - hash = crypto.SHA256 - case ECDSAP384SHA384: - hash = crypto.SHA384 - case RSASHA512: - hash = crypto.SHA512 - default: - return nil, ErrAlg - } - hasher := hash.New() - // Write SIG rdata - hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) - // Write message - hasher.Write(buf[:len(mbuf)]) - hashed := hasher.Sum(nil) - - sig, err := k.Sign(hashed, rr.Algorithm) - if err != nil { - return nil, err - } - rr.Signature = toBase64(sig) - buf = append(buf, sig...) - if len(buf) > int(^uint16(0)) { - return nil, ErrBuf - } - // Adjust sig data length - rdoff := len(mbuf) + 1 + 2 + 2 + 4 - rdlen, _ := unpackUint16(buf, rdoff) - rdlen += uint16(len(sig)) - buf[rdoff], buf[rdoff+1] = packUint16(rdlen) - // Adjust additional count - adc, _ := unpackUint16(buf, 10) - adc++ - buf[10], buf[11] = packUint16(adc) - return buf, nil -} - -// Verify validates the message buf using the key k. -// It's assumed that buf is a valid message from which rr was unpacked. -func (rr *SIG) Verify(k *KEY, buf []byte) error { - if k == nil { - return ErrKey - } - if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { - return ErrKey - } - - var hash crypto.Hash - switch rr.Algorithm { - case DSA, RSASHA1: - hash = crypto.SHA1 - case RSASHA256, ECDSAP256SHA256: - hash = crypto.SHA256 - case ECDSAP384SHA384: - hash = crypto.SHA384 - case RSASHA512: - hash = crypto.SHA512 - default: - return ErrAlg - } - hasher := hash.New() - - buflen := len(buf) - qdc, _ := unpackUint16(buf, 4) - anc, _ := unpackUint16(buf, 6) - auc, _ := unpackUint16(buf, 8) - adc, offset := unpackUint16(buf, 10) - var err error - for i := uint16(0); i < qdc && offset < buflen; i++ { - _, offset, err = UnpackDomainName(buf, offset) - if err != nil { - return err - } - // Skip past Type and Class - offset += 2 + 2 - } - for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ { - _, offset, err = UnpackDomainName(buf, offset) - if err != nil { - return err - } - // Skip past Type, Class and TTL - offset += 2 + 2 + 4 - if offset+1 >= buflen { - continue - } - var rdlen uint16 - rdlen, offset = unpackUint16(buf, offset) - offset += int(rdlen) - } - if offset >= buflen { - return &Error{err: "overflowing unpacking signed message"} - } - - // offset should be just prior to SIG - bodyend := offset - // owner name SHOULD be root - _, offset, err = UnpackDomainName(buf, offset) - if err != nil { - return err - } - // Skip Type, Class, TTL, RDLen - offset += 2 + 2 + 4 + 2 - sigstart := offset - // Skip Type Covered, Algorithm, Labels, Original TTL - offset += 2 + 1 + 1 + 4 - if offset+4+4 >= buflen { - return &Error{err: "overflow unpacking signed message"} - } - expire := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3]) - offset += 4 - incept := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3]) - offset += 4 - now := uint32(time.Now().Unix()) - if now < incept || now > expire { - return ErrTime - } - // Skip key tag - offset += 2 - var signername string - signername, offset, err = UnpackDomainName(buf, offset) - if err != nil { - return err - } - // If key has come from the DNS name compression might - // have mangled the case of the name - if strings.ToLower(signername) != strings.ToLower(k.Header().Name) { - return &Error{err: "signer name doesn't match key name"} - } - sigend := offset - hasher.Write(buf[sigstart:sigend]) - hasher.Write(buf[:10]) - hasher.Write([]byte{ - byte((adc - 1) << 8), - byte(adc - 1), - }) - hasher.Write(buf[12:bodyend]) - - hashed := hasher.Sum(nil) - sig := buf[sigend:] - switch k.Algorithm { - case DSA: - pk := k.publicKeyDSA() - sig = sig[1:] - r := big.NewInt(0) - r.SetBytes(sig[:len(sig)/2]) - s := big.NewInt(0) - s.SetBytes(sig[len(sig)/2:]) - if pk != nil { - if dsa.Verify(pk, hashed, r, s) { - return nil - } - return ErrSig - } - case RSASHA1, RSASHA256, RSASHA512: - pk := k.publicKeyRSA() - if pk != nil { - return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) - } - case ECDSAP256SHA256, ECDSAP384SHA384: - pk := k.publicKeyECDSA() - r := big.NewInt(0) - r.SetBytes(sig[:len(sig)/2]) - s := big.NewInt(0) - s.SetBytes(sig[len(sig)/2:]) - if pk != nil { - if ecdsa.Verify(pk, hashed, r, s) { - return nil - } - return ErrSig - } - } - return ErrKeyAlg -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go b/Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go deleted file mode 100644 index cdd57ab81..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package dns - -import ( - "testing" - "time" -) - -func TestSIG0(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - m := new(Msg) - m.SetQuestion("example.org.", TypeSOA) - for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} { - algstr := AlgorithmToString[alg] - keyrr := new(KEY) - keyrr.Hdr.Name = algstr + "." - keyrr.Hdr.Rrtype = TypeKEY - keyrr.Hdr.Class = ClassINET - keyrr.Algorithm = alg - keysize := 1024 - switch alg { - case ECDSAP256SHA256: - keysize = 256 - case ECDSAP384SHA384: - keysize = 384 - } - pk, err := keyrr.Generate(keysize) - if err != nil { - t.Errorf("Failed to generate key for “%s”: %v", algstr, err) - continue - } - now := uint32(time.Now().Unix()) - sigrr := new(SIG) - sigrr.Hdr.Name = "." - sigrr.Hdr.Rrtype = TypeSIG - sigrr.Hdr.Class = ClassANY - sigrr.Algorithm = alg - sigrr.Expiration = now + 300 - sigrr.Inception = now - 300 - sigrr.KeyTag = keyrr.KeyTag() - sigrr.SignerName = keyrr.Hdr.Name - mb, err := sigrr.Sign(pk, m) - if err != nil { - t.Errorf("Failed to sign message using “%s”: %v", algstr, err) - continue - } - m := new(Msg) - if err := m.Unpack(mb); err != nil { - t.Errorf("Failed to unpack message signed using “%s”: %v", algstr, err) - continue - } - if len(m.Extra) != 1 { - t.Errorf("Missing SIG for message signed using “%s”", algstr) - continue - } - var sigrrwire *SIG - switch rr := m.Extra[0].(type) { - case *SIG: - sigrrwire = rr - default: - t.Errorf("Expected SIG RR, instead: %v", rr) - continue - } - for _, rr := range []*SIG{sigrr, sigrrwire} { - id := "sigrr" - if rr == sigrrwire { - id = "sigrrwire" - } - if err := rr.Verify(keyrr, mb); err != nil { - t.Errorf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err) - continue - } - } - mb[13]++ - if err := sigrr.Verify(keyrr, mb); err == nil { - t.Errorf("Verify succeeded on an altered message using “%s”", algstr) - continue - } - sigrr.Expiration = 2 - sigrr.Inception = 1 - mb, _ = sigrr.Sign(pk, m) - if err := sigrr.Verify(keyrr, mb); err == nil { - t.Errorf("Verify succeeded on an expired message using “%s”", algstr) - continue - } - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go b/Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go deleted file mode 100644 index 9573c7d0b..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Adapted for dns package usage by Miek Gieben. - -package dns - -import "sync" -import "time" - -// call is an in-flight or completed singleflight.Do call -type call struct { - wg sync.WaitGroup - val *Msg - rtt time.Duration - err error - dups int -} - -// singleflight represents a class of work and forms a namespace in -// which units of work can be executed with duplicate suppression. -type singleflight struct { - sync.Mutex // protects m - m map[string]*call // lazily initialized -} - -// Do executes and returns the results of the given function, making -// sure that only one execution is in-flight for a given key at a -// time. If a duplicate comes in, the duplicate caller waits for the -// original to complete and receives the same results. -// The return value shared indicates whether v was given to multiple callers. -func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) { - g.Lock() - if g.m == nil { - g.m = make(map[string]*call) - } - if c, ok := g.m[key]; ok { - c.dups++ - g.Unlock() - c.wg.Wait() - return c.val, c.rtt, c.err, true - } - c := new(call) - c.wg.Add(1) - g.m[key] = c - g.Unlock() - - c.val, c.rtt, c.err = fn() - c.wg.Done() - - g.Lock() - delete(g.m, key) - g.Unlock() - - return c.val, c.rtt, c.err, c.dups > 0 -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/tlsa.go b/Godeps/_workspace/src/github.com/miekg/dns/tlsa.go deleted file mode 100644 index f027787df..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/tlsa.go +++ /dev/null @@ -1,86 +0,0 @@ -package dns - -import ( - "crypto/sha256" - "crypto/sha512" - "crypto/x509" - "encoding/hex" - "errors" - "io" - "net" - "strconv" -) - -// CertificateToDANE converts a certificate to a hex string as used in the TLSA record. -func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) { - switch matchingType { - case 0: - switch selector { - case 0: - return hex.EncodeToString(cert.Raw), nil - case 1: - return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil - } - case 1: - h := sha256.New() - switch selector { - case 0: - io.WriteString(h, string(cert.Raw)) - return hex.EncodeToString(h.Sum(nil)), nil - case 1: - io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) - return hex.EncodeToString(h.Sum(nil)), nil - } - case 2: - h := sha512.New() - switch selector { - case 0: - io.WriteString(h, string(cert.Raw)) - return hex.EncodeToString(h.Sum(nil)), nil - case 1: - io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) - return hex.EncodeToString(h.Sum(nil)), nil - } - } - return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector") -} - -// Sign creates a TLSA record from an SSL certificate. -func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) { - r.Hdr.Rrtype = TypeTLSA - r.Usage = uint8(usage) - r.Selector = uint8(selector) - r.MatchingType = uint8(matchingType) - - r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert) - if err != nil { - return err - } - return nil -} - -// Verify verifies a TLSA record against an SSL certificate. If it is OK -// a nil error is returned. -func (r *TLSA) Verify(cert *x509.Certificate) error { - c, err := CertificateToDANE(r.Selector, r.MatchingType, cert) - if err != nil { - return err // Not also ErrSig? - } - if r.Certificate == c { - return nil - } - return ErrSig // ErrSig, really? -} - -// TLSAName returns the ownername of a TLSA resource record as per the -// rules specified in RFC 6698, Section 3. -func TLSAName(name, service, network string) (string, error) { - if !IsFqdn(name) { - return "", ErrFqdn - } - p, e := net.LookupPort(network, service) - if e != nil { - return "", e - } - return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/tsig.go b/Godeps/_workspace/src/github.com/miekg/dns/tsig.go deleted file mode 100644 index d7bc25056..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/tsig.go +++ /dev/null @@ -1,333 +0,0 @@ -package dns - -import ( - "crypto/hmac" - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/hex" - "hash" - "io" - "strconv" - "strings" - "time" -) - -// HMAC hashing codes. These are transmitted as domain names. -const ( - HmacMD5 = "hmac-md5.sig-alg.reg.int." - HmacSHA1 = "hmac-sha1." - HmacSHA256 = "hmac-sha256." - HmacSHA512 = "hmac-sha512." -) - -// TSIG is the RR the holds the transaction signature of a message. -// See RFC 2845 and RFC 4635. -type TSIG struct { - Hdr RR_Header - Algorithm string `dns:"domain-name"` - TimeSigned uint64 `dns:"uint48"` - Fudge uint16 - MACSize uint16 - MAC string `dns:"size-hex"` - OrigId uint16 - Error uint16 - OtherLen uint16 - OtherData string `dns:"size-hex"` -} - -func (rr *TSIG) Header() *RR_Header { - return &rr.Hdr -} - -// TSIG has no official presentation format, but this will suffice. - -func (rr *TSIG) String() string { - s := "\n;; TSIG PSEUDOSECTION:\n" - s += rr.Hdr.String() + - " " + rr.Algorithm + - " " + tsigTimeToString(rr.TimeSigned) + - " " + strconv.Itoa(int(rr.Fudge)) + - " " + strconv.Itoa(int(rr.MACSize)) + - " " + strings.ToUpper(rr.MAC) + - " " + strconv.Itoa(int(rr.OrigId)) + - " " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR - " " + strconv.Itoa(int(rr.OtherLen)) + - " " + rr.OtherData - return s -} - -func (rr *TSIG) len() int { - return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 + - 4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1 -} - -func (rr *TSIG) copy() RR { - return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData} -} - -// The following values must be put in wireformat, so that the MAC can be calculated. -// RFC 2845, section 3.4.2. TSIG Variables. -type tsigWireFmt struct { - // From RR_Header - Name string `dns:"domain-name"` - Class uint16 - Ttl uint32 - // Rdata of the TSIG - Algorithm string `dns:"domain-name"` - TimeSigned uint64 `dns:"uint48"` - Fudge uint16 - // MACSize, MAC and OrigId excluded - Error uint16 - OtherLen uint16 - OtherData string `dns:"size-hex"` -} - -// If we have the MAC use this type to convert it to wiredata. -// Section 3.4.3. Request MAC -type macWireFmt struct { - MACSize uint16 - MAC string `dns:"size-hex"` -} - -// 3.3. Time values used in TSIG calculations -type timerWireFmt struct { - TimeSigned uint64 `dns:"uint48"` - Fudge uint16 -} - -// TsigGenerate fills out the TSIG record attached to the message. -// The message should contain -// a "stub" TSIG RR with the algorithm, key name (owner name of the RR), -// time fudge (defaults to 300 seconds) and the current time -// The TSIG MAC is saved in that Tsig RR. -// When TsigGenerate is called for the first time requestMAC is set to the empty string and -// timersOnly is false. -// If something goes wrong an error is returned, otherwise it is nil. -func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { - if m.IsTsig() == nil { - panic("dns: TSIG not last RR in additional") - } - // If we barf here, the caller is to blame - rawsecret, err := fromBase64([]byte(secret)) - if err != nil { - return nil, "", err - } - - rr := m.Extra[len(m.Extra)-1].(*TSIG) - m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg - mbuf, err := m.Pack() - if err != nil { - return nil, "", err - } - buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly) - - t := new(TSIG) - var h hash.Hash - switch rr.Algorithm { - case HmacMD5: - h = hmac.New(md5.New, []byte(rawsecret)) - case HmacSHA1: - h = hmac.New(sha1.New, []byte(rawsecret)) - case HmacSHA256: - h = hmac.New(sha256.New, []byte(rawsecret)) - case HmacSHA512: - h = hmac.New(sha512.New, []byte(rawsecret)) - default: - return nil, "", ErrKeyAlg - } - io.WriteString(h, string(buf)) - t.MAC = hex.EncodeToString(h.Sum(nil)) - t.MACSize = uint16(len(t.MAC) / 2) // Size is half! - - t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0} - t.Fudge = rr.Fudge - t.TimeSigned = rr.TimeSigned - t.Algorithm = rr.Algorithm - t.OrigId = m.Id - - tbuf := make([]byte, t.len()) - if off, err := PackRR(t, tbuf, 0, nil, false); err == nil { - tbuf = tbuf[:off] // reset to actual size used - } else { - return nil, "", err - } - mbuf = append(mbuf, tbuf...) - rawSetExtraLen(mbuf, uint16(len(m.Extra)+1)) - return mbuf, t.MAC, nil -} - -// TsigVerify verifies the TSIG on a message. -// If the signature does not validate err contains the -// error, otherwise it is nil. -func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { - rawsecret, err := fromBase64([]byte(secret)) - if err != nil { - return err - } - // Strip the TSIG from the incoming msg - stripped, tsig, err := stripTsig(msg) - if err != nil { - return err - } - - msgMAC, err := hex.DecodeString(tsig.MAC) - if err != nil { - return err - } - - buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly) - - // Fudge factor works both ways. A message can arrive before it was signed because - // of clock skew. - now := uint64(time.Now().Unix()) - ti := now - tsig.TimeSigned - if now < tsig.TimeSigned { - ti = tsig.TimeSigned - now - } - if uint64(tsig.Fudge) < ti { - return ErrTime - } - - var h hash.Hash - switch tsig.Algorithm { - case HmacMD5: - h = hmac.New(md5.New, rawsecret) - case HmacSHA1: - h = hmac.New(sha1.New, rawsecret) - case HmacSHA256: - h = hmac.New(sha256.New, rawsecret) - case HmacSHA512: - h = hmac.New(sha512.New, rawsecret) - default: - return ErrKeyAlg - } - h.Write(buf) - if !hmac.Equal(h.Sum(nil), msgMAC) { - return ErrSig - } - return nil -} - -// Create a wiredata buffer for the MAC calculation. -func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte { - var buf []byte - if rr.TimeSigned == 0 { - rr.TimeSigned = uint64(time.Now().Unix()) - } - if rr.Fudge == 0 { - rr.Fudge = 300 // Standard (RFC) default. - } - - if requestMAC != "" { - m := new(macWireFmt) - m.MACSize = uint16(len(requestMAC) / 2) - m.MAC = requestMAC - buf = make([]byte, len(requestMAC)) // long enough - n, _ := PackStruct(m, buf, 0) - buf = buf[:n] - } - - tsigvar := make([]byte, DefaultMsgSize) - if timersOnly { - tsig := new(timerWireFmt) - tsig.TimeSigned = rr.TimeSigned - tsig.Fudge = rr.Fudge - n, _ := PackStruct(tsig, tsigvar, 0) - tsigvar = tsigvar[:n] - } else { - tsig := new(tsigWireFmt) - tsig.Name = strings.ToLower(rr.Hdr.Name) - tsig.Class = ClassANY - tsig.Ttl = rr.Hdr.Ttl - tsig.Algorithm = strings.ToLower(rr.Algorithm) - tsig.TimeSigned = rr.TimeSigned - tsig.Fudge = rr.Fudge - tsig.Error = rr.Error - tsig.OtherLen = rr.OtherLen - tsig.OtherData = rr.OtherData - n, _ := PackStruct(tsig, tsigvar, 0) - tsigvar = tsigvar[:n] - } - - if requestMAC != "" { - x := append(buf, msgbuf...) - buf = append(x, tsigvar...) - } else { - buf = append(msgbuf, tsigvar...) - } - return buf -} - -// Strip the TSIG from the raw message. -func stripTsig(msg []byte) ([]byte, *TSIG, error) { - // Copied from msg.go's Unpack() - // Header. - var dh Header - var err error - dns := new(Msg) - rr := new(TSIG) - off := 0 - tsigoff := 0 - if off, err = UnpackStruct(&dh, msg, off); err != nil { - return nil, nil, err - } - if dh.Arcount == 0 { - return nil, nil, ErrNoSig - } - // Rcode, see msg.go Unpack() - if int(dh.Bits&0xF) == RcodeNotAuth { - return nil, nil, ErrAuth - } - - // Arrays. - dns.Question = make([]Question, dh.Qdcount) - dns.Answer = make([]RR, dh.Ancount) - dns.Ns = make([]RR, dh.Nscount) - dns.Extra = make([]RR, dh.Arcount) - - for i := 0; i < len(dns.Question); i++ { - off, err = UnpackStruct(&dns.Question[i], msg, off) - if err != nil { - return nil, nil, err - } - } - for i := 0; i < len(dns.Answer); i++ { - dns.Answer[i], off, err = UnpackRR(msg, off) - if err != nil { - return nil, nil, err - } - } - for i := 0; i < len(dns.Ns); i++ { - dns.Ns[i], off, err = UnpackRR(msg, off) - if err != nil { - return nil, nil, err - } - } - for i := 0; i < len(dns.Extra); i++ { - tsigoff = off - dns.Extra[i], off, err = UnpackRR(msg, off) - if err != nil { - return nil, nil, err - } - if dns.Extra[i].Header().Rrtype == TypeTSIG { - rr = dns.Extra[i].(*TSIG) - // Adjust Arcount. - arcount, _ := unpackUint16(msg, 10) - msg[10], msg[11] = packUint16(arcount - 1) - break - } - } - if rr == nil { - return nil, nil, ErrNoSig - } - return msg[:tsigoff], rr, nil -} - -// Translate the TSIG time signed into a date. There is no -// need for RFC1982 calculations as this date is 48 bits. -func tsigTimeToString(t uint64) string { - ti := time.Unix(int64(t), 0).UTC() - return ti.Format("20060102150405") -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/types.go b/Godeps/_workspace/src/github.com/miekg/dns/types.go deleted file mode 100644 index 40cc0a4f4..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/types.go +++ /dev/null @@ -1,1737 +0,0 @@ -package dns - -import ( - "encoding/base64" - "fmt" - "net" - "strconv" - "strings" - "time" -) - -type ( - // Type is a DNS type. - Type uint16 - // Class is a DNS class. - Class uint16 - // Name is a DNS domain name. - Name string -) - -// Packet formats - -// Wire constants and supported types. -const ( - // valid RR_Header.Rrtype and Question.qtype - - TypeNone uint16 = 0 - TypeA uint16 = 1 - TypeNS uint16 = 2 - TypeMD uint16 = 3 - TypeMF uint16 = 4 - TypeCNAME uint16 = 5 - TypeSOA uint16 = 6 - TypeMB uint16 = 7 - TypeMG uint16 = 8 - TypeMR uint16 = 9 - TypeNULL uint16 = 10 - TypeWKS uint16 = 11 - TypePTR uint16 = 12 - TypeHINFO uint16 = 13 - TypeMINFO uint16 = 14 - TypeMX uint16 = 15 - TypeTXT uint16 = 16 - TypeRP uint16 = 17 - TypeAFSDB uint16 = 18 - TypeX25 uint16 = 19 - TypeISDN uint16 = 20 - TypeRT uint16 = 21 - TypeNSAP uint16 = 22 - TypeNSAPPTR uint16 = 23 - TypeSIG uint16 = 24 - TypeKEY uint16 = 25 - TypePX uint16 = 26 - TypeGPOS uint16 = 27 - TypeAAAA uint16 = 28 - TypeLOC uint16 = 29 - TypeNXT uint16 = 30 - TypeEID uint16 = 31 - TypeNIMLOC uint16 = 32 - TypeSRV uint16 = 33 - TypeATMA uint16 = 34 - TypeNAPTR uint16 = 35 - TypeKX uint16 = 36 - TypeCERT uint16 = 37 - TypeDNAME uint16 = 39 - TypeOPT uint16 = 41 // EDNS - TypeDS uint16 = 43 - TypeSSHFP uint16 = 44 - TypeIPSECKEY uint16 = 45 - TypeRRSIG uint16 = 46 - TypeNSEC uint16 = 47 - TypeDNSKEY uint16 = 48 - TypeDHCID uint16 = 49 - TypeNSEC3 uint16 = 50 - TypeNSEC3PARAM uint16 = 51 - TypeTLSA uint16 = 52 - TypeHIP uint16 = 55 - TypeNINFO uint16 = 56 - TypeRKEY uint16 = 57 - TypeTALINK uint16 = 58 - TypeCDS uint16 = 59 - TypeCDNSKEY uint16 = 60 - TypeOPENPGPKEY uint16 = 61 - TypeSPF uint16 = 99 - TypeUINFO uint16 = 100 - TypeUID uint16 = 101 - TypeGID uint16 = 102 - TypeUNSPEC uint16 = 103 - TypeNID uint16 = 104 - TypeL32 uint16 = 105 - TypeL64 uint16 = 106 - TypeLP uint16 = 107 - TypeEUI48 uint16 = 108 - TypeEUI64 uint16 = 109 - - TypeTKEY uint16 = 249 - TypeTSIG uint16 = 250 - - // valid Question.Qtype only - - TypeIXFR uint16 = 251 - TypeAXFR uint16 = 252 - TypeMAILB uint16 = 253 - TypeMAILA uint16 = 254 - TypeANY uint16 = 255 - - TypeURI uint16 = 256 - TypeCAA uint16 = 257 - TypeTA uint16 = 32768 - TypeDLV uint16 = 32769 - TypeReserved uint16 = 65535 - - // valid Question.Qclass - - ClassINET = 1 - ClassCSNET = 2 - ClassCHAOS = 3 - ClassHESIOD = 4 - ClassNONE = 254 - ClassANY = 255 - - // Msg.rcode - - RcodeSuccess = 0 - RcodeFormatError = 1 - RcodeServerFailure = 2 - RcodeNameError = 3 - RcodeNotImplemented = 4 - RcodeRefused = 5 - RcodeYXDomain = 6 - RcodeYXRrset = 7 - RcodeNXRrset = 8 - RcodeNotAuth = 9 - RcodeNotZone = 10 - RcodeBadSig = 16 // TSIG - RcodeBadVers = 16 // EDNS0 - RcodeBadKey = 17 - RcodeBadTime = 18 - RcodeBadMode = 19 // TKEY - RcodeBadName = 20 - RcodeBadAlg = 21 - RcodeBadTrunc = 22 // TSIG - - // Opcode, there is no 3 - - OpcodeQuery = 0 - OpcodeIQuery = 1 - OpcodeStatus = 2 - OpcodeNotify = 4 - OpcodeUpdate = 5 -) - -// The wire format for the DNS packet header. -type Header struct { - Id uint16 - Bits uint16 - Qdcount, Ancount, Nscount, Arcount uint16 -} - -const ( - // Header.Bits - _QR = 1 << 15 // query/response (response=1) - _AA = 1 << 10 // authoritative - _TC = 1 << 9 // truncated - _RD = 1 << 8 // recursion desired - _RA = 1 << 7 // recursion available - _Z = 1 << 6 // Z - _AD = 1 << 5 // authticated data - _CD = 1 << 4 // checking disabled - - LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2. - LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2. - - LOC_HOURS = 60 * 1000 - LOC_DEGREES = 60 * LOC_HOURS - - LOC_ALTITUDEBASE = 100000 -) - -// RFC 4398, Section 2.1 -const ( - CertPKIX = 1 + iota - CertSPKI - CertPGP - CertIPIX - CertISPKI - CertIPGP - CertACPKIX - CertIACPKIX - CertURI = 253 - CertOID = 254 -) - -var CertTypeToString = map[uint16]string{ - CertPKIX: "PKIX", - CertSPKI: "SPKI", - CertPGP: "PGP", - CertIPIX: "IPIX", - CertISPKI: "ISPKI", - CertIPGP: "IPGP", - CertACPKIX: "ACPKIX", - CertIACPKIX: "IACPKIX", - CertURI: "URI", - CertOID: "OID", -} - -var StringToCertType = reverseInt16(CertTypeToString) - -// Question holds a DNS question. There can be multiple questions in the -// question section of a message. Usually there is just one. -type Question struct { - Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed) - Qtype uint16 - Qclass uint16 -} - -func (q *Question) String() (s string) { - // prefix with ; (as in dig) - s = ";" + sprintName(q.Name) + "\t" - s += Class(q.Qclass).String() + "\t" - s += " " + Type(q.Qtype).String() - return s -} - -func (q *Question) len() int { - l := len(q.Name) + 1 - return l + 4 -} - -type ANY struct { - Hdr RR_Header - // Does not have any rdata -} - -func (rr *ANY) Header() *RR_Header { return &rr.Hdr } -func (rr *ANY) copy() RR { return &ANY{*rr.Hdr.copyHeader()} } -func (rr *ANY) String() string { return rr.Hdr.String() } -func (rr *ANY) len() int { return rr.Hdr.len() } - -type CNAME struct { - Hdr RR_Header - Target string `dns:"cdomain-name"` -} - -func (rr *CNAME) Header() *RR_Header { return &rr.Hdr } -func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), sprintName(rr.Target)} } -func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target } -func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 } - -type HINFO struct { - Hdr RR_Header - Cpu string - Os string -} - -func (rr *HINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *HINFO) copy() RR { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} } -func (rr *HINFO) String() string { return rr.Hdr.String() + rr.Cpu + " " + rr.Os } -func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) } - -type MB struct { - Hdr RR_Header - Mb string `dns:"cdomain-name"` -} - -func (rr *MB) Header() *RR_Header { return &rr.Hdr } -func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), sprintName(rr.Mb)} } - -func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb } -func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 } - -type MG struct { - Hdr RR_Header - Mg string `dns:"cdomain-name"` -} - -func (rr *MG) Header() *RR_Header { return &rr.Hdr } -func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} } -func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l } -func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) } - -type MINFO struct { - Hdr RR_Header - Rmail string `dns:"cdomain-name"` - Email string `dns:"cdomain-name"` -} - -func (rr *MINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} } - -func (rr *MINFO) String() string { - return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email) -} - -func (rr *MINFO) len() int { - l := len(rr.Rmail) + 1 - n := len(rr.Email) + 1 - return rr.Hdr.len() + l + n -} - -type MR struct { - Hdr RR_Header - Mr string `dns:"cdomain-name"` -} - -func (rr *MR) Header() *RR_Header { return &rr.Hdr } -func (rr *MR) copy() RR { return &MR{*rr.Hdr.copyHeader(), rr.Mr} } -func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l } - -func (rr *MR) String() string { - return rr.Hdr.String() + sprintName(rr.Mr) -} - -type MF struct { - Hdr RR_Header - Mf string `dns:"cdomain-name"` -} - -func (rr *MF) Header() *RR_Header { return &rr.Hdr } -func (rr *MF) copy() RR { return &MF{*rr.Hdr.copyHeader(), rr.Mf} } -func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 } - -func (rr *MF) String() string { - return rr.Hdr.String() + sprintName(rr.Mf) -} - -type MD struct { - Hdr RR_Header - Md string `dns:"cdomain-name"` -} - -func (rr *MD) Header() *RR_Header { return &rr.Hdr } -func (rr *MD) copy() RR { return &MD{*rr.Hdr.copyHeader(), rr.Md} } -func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 } - -func (rr *MD) String() string { - return rr.Hdr.String() + sprintName(rr.Md) -} - -type MX struct { - Hdr RR_Header - Preference uint16 - Mx string `dns:"cdomain-name"` -} - -func (rr *MX) Header() *RR_Header { return &rr.Hdr } -func (rr *MX) copy() RR { return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} } -func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 } - -func (rr *MX) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx) -} - -type AFSDB struct { - Hdr RR_Header - Subtype uint16 - Hostname string `dns:"cdomain-name"` -} - -func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr } -func (rr *AFSDB) copy() RR { return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} } -func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 } - -func (rr *AFSDB) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname) -} - -type X25 struct { - Hdr RR_Header - PSDNAddress string -} - -func (rr *X25) Header() *RR_Header { return &rr.Hdr } -func (rr *X25) copy() RR { return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} } -func (rr *X25) len() int { return rr.Hdr.len() + len(rr.PSDNAddress) + 1 } - -func (rr *X25) String() string { - return rr.Hdr.String() + rr.PSDNAddress -} - -type RT struct { - Hdr RR_Header - Preference uint16 - Host string `dns:"cdomain-name"` -} - -func (rr *RT) Header() *RR_Header { return &rr.Hdr } -func (rr *RT) copy() RR { return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} } -func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 } - -func (rr *RT) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host) -} - -type NS struct { - Hdr RR_Header - Ns string `dns:"cdomain-name"` -} - -func (rr *NS) Header() *RR_Header { return &rr.Hdr } -func (rr *NS) len() int { l := len(rr.Ns) + 1; return rr.Hdr.len() + l } -func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} } - -func (rr *NS) String() string { - return rr.Hdr.String() + sprintName(rr.Ns) -} - -type PTR struct { - Hdr RR_Header - Ptr string `dns:"cdomain-name"` -} - -func (rr *PTR) Header() *RR_Header { return &rr.Hdr } -func (rr *PTR) copy() RR { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} } -func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l } - -func (rr *PTR) String() string { - return rr.Hdr.String() + sprintName(rr.Ptr) -} - -type RP struct { - Hdr RR_Header - Mbox string `dns:"domain-name"` - Txt string `dns:"domain-name"` -} - -func (rr *RP) Header() *RR_Header { return &rr.Hdr } -func (rr *RP) copy() RR { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} } -func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 } - -func (rr *RP) String() string { - return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt}) -} - -type SOA struct { - Hdr RR_Header - Ns string `dns:"cdomain-name"` - Mbox string `dns:"cdomain-name"` - Serial uint32 - Refresh uint32 - Retry uint32 - Expire uint32 - Minttl uint32 -} - -func (rr *SOA) Header() *RR_Header { return &rr.Hdr } -func (rr *SOA) copy() RR { - return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl} -} - -func (rr *SOA) String() string { - return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) + - " " + strconv.FormatInt(int64(rr.Serial), 10) + - " " + strconv.FormatInt(int64(rr.Refresh), 10) + - " " + strconv.FormatInt(int64(rr.Retry), 10) + - " " + strconv.FormatInt(int64(rr.Expire), 10) + - " " + strconv.FormatInt(int64(rr.Minttl), 10) -} - -func (rr *SOA) len() int { - l := len(rr.Ns) + 1 - n := len(rr.Mbox) + 1 - return rr.Hdr.len() + l + n + 20 -} - -type TXT struct { - Hdr RR_Header - Txt []string `dns:"txt"` -} - -func (rr *TXT) Header() *RR_Header { return &rr.Hdr } -func (rr *TXT) copy() RR { - cp := make([]string, len(rr.Txt), cap(rr.Txt)) - copy(cp, rr.Txt) - return &TXT{*rr.Hdr.copyHeader(), cp} -} - -func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } - -func sprintName(s string) string { - src := []byte(s) - dst := make([]byte, 0, len(src)) - for i := 0; i < len(src); { - if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' { - dst = append(dst, src[i:i+2]...) - i += 2 - } else { - b, n := nextByte(src, i) - if n == 0 { - i++ // dangling back slash - } else if b == '.' { - dst = append(dst, b) - } else { - dst = appendDomainNameByte(dst, b) - } - i += n - } - } - return string(dst) -} - -func sprintTxt(txt []string) string { - var out []byte - for i, s := range txt { - if i > 0 { - out = append(out, ` "`...) - } else { - out = append(out, '"') - } - bs := []byte(s) - for j := 0; j < len(bs); { - b, n := nextByte(bs, j) - if n == 0 { - break - } - out = appendTXTStringByte(out, b) - j += n - } - out = append(out, '"') - } - return string(out) -} - -func appendDomainNameByte(s []byte, b byte) []byte { - switch b { - case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape - return append(s, '\\', b) - } - return appendTXTStringByte(s, b) -} - -func appendTXTStringByte(s []byte, b byte) []byte { - switch b { - case '\t': - return append(s, '\\', 't') - case '\r': - return append(s, '\\', 'r') - case '\n': - return append(s, '\\', 'n') - case '"', '\\': - return append(s, '\\', b) - } - if b < ' ' || b > '~' { - var buf [3]byte - bufs := strconv.AppendInt(buf[:0], int64(b), 10) - s = append(s, '\\') - for i := 0; i < 3-len(bufs); i++ { - s = append(s, '0') - } - for _, r := range bufs { - s = append(s, r) - } - return s - - } - return append(s, b) -} - -func nextByte(b []byte, offset int) (byte, int) { - if offset >= len(b) { - return 0, 0 - } - if b[offset] != '\\' { - // not an escape sequence - return b[offset], 1 - } - switch len(b) - offset { - case 1: // dangling escape - return 0, 0 - case 2, 3: // too short to be \ddd - default: // maybe \ddd - if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) { - return dddToByte(b[offset+1:]), 4 - } - } - // not \ddd, maybe a control char - switch b[offset+1] { - case 't': - return '\t', 2 - case 'r': - return '\r', 2 - case 'n': - return '\n', 2 - default: - return b[offset+1], 2 - } -} - -func (rr *TXT) len() int { - l := rr.Hdr.len() - for _, t := range rr.Txt { - l += len(t) + 1 - } - return l -} - -type SPF struct { - Hdr RR_Header - Txt []string `dns:"txt"` -} - -func (rr *SPF) Header() *RR_Header { return &rr.Hdr } -func (rr *SPF) copy() RR { - cp := make([]string, len(rr.Txt), cap(rr.Txt)) - copy(cp, rr.Txt) - return &SPF{*rr.Hdr.copyHeader(), cp} -} - -func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } - -func (rr *SPF) len() int { - l := rr.Hdr.len() - for _, t := range rr.Txt { - l += len(t) + 1 - } - return l -} - -type SRV struct { - Hdr RR_Header - Priority uint16 - Weight uint16 - Port uint16 - Target string `dns:"domain-name"` -} - -func (rr *SRV) Header() *RR_Header { return &rr.Hdr } -func (rr *SRV) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l + 6 } -func (rr *SRV) copy() RR { - return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target} -} - -func (rr *SRV) String() string { - return rr.Hdr.String() + - strconv.Itoa(int(rr.Priority)) + " " + - strconv.Itoa(int(rr.Weight)) + " " + - strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target) -} - -type NAPTR struct { - Hdr RR_Header - Order uint16 - Preference uint16 - Flags string - Service string - Regexp string - Replacement string `dns:"domain-name"` -} - -func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr } -func (rr *NAPTR) copy() RR { - return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement} -} - -func (rr *NAPTR) String() string { - return rr.Hdr.String() + - strconv.Itoa(int(rr.Order)) + " " + - strconv.Itoa(int(rr.Preference)) + " " + - "\"" + rr.Flags + "\" " + - "\"" + rr.Service + "\" " + - "\"" + rr.Regexp + "\" " + - rr.Replacement -} - -func (rr *NAPTR) len() int { - return rr.Hdr.len() + 4 + len(rr.Flags) + 1 + len(rr.Service) + 1 + - len(rr.Regexp) + 1 + len(rr.Replacement) + 1 -} - -// See RFC 4398. -type CERT struct { - Hdr RR_Header - Type uint16 - KeyTag uint16 - Algorithm uint8 - Certificate string `dns:"base64"` -} - -func (rr *CERT) Header() *RR_Header { return &rr.Hdr } -func (rr *CERT) copy() RR { - return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate} -} - -func (rr *CERT) String() string { - var ( - ok bool - certtype, algorithm string - ) - if certtype, ok = CertTypeToString[rr.Type]; !ok { - certtype = strconv.Itoa(int(rr.Type)) - } - if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok { - algorithm = strconv.Itoa(int(rr.Algorithm)) - } - return rr.Hdr.String() + certtype + - " " + strconv.Itoa(int(rr.KeyTag)) + - " " + algorithm + - " " + rr.Certificate -} - -func (rr *CERT) len() int { - return rr.Hdr.len() + 5 + - base64.StdEncoding.DecodedLen(len(rr.Certificate)) -} - -// See RFC 2672. -type DNAME struct { - Hdr RR_Header - Target string `dns:"domain-name"` -} - -func (rr *DNAME) Header() *RR_Header { return &rr.Hdr } -func (rr *DNAME) copy() RR { return &DNAME{*rr.Hdr.copyHeader(), rr.Target} } -func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l } - -func (rr *DNAME) String() string { - return rr.Hdr.String() + sprintName(rr.Target) -} - -type A struct { - Hdr RR_Header - A net.IP `dns:"a"` -} - -func (rr *A) Header() *RR_Header { return &rr.Hdr } -func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} } -func (rr *A) len() int { return rr.Hdr.len() + net.IPv4len } - -func (rr *A) String() string { - if rr.A == nil { - return rr.Hdr.String() - } - return rr.Hdr.String() + rr.A.String() -} - -type AAAA struct { - Hdr RR_Header - AAAA net.IP `dns:"aaaa"` -} - -func (rr *AAAA) Header() *RR_Header { return &rr.Hdr } -func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} } -func (rr *AAAA) len() int { return rr.Hdr.len() + net.IPv6len } - -func (rr *AAAA) String() string { - if rr.AAAA == nil { - return rr.Hdr.String() - } - return rr.Hdr.String() + rr.AAAA.String() -} - -type PX struct { - Hdr RR_Header - Preference uint16 - Map822 string `dns:"domain-name"` - Mapx400 string `dns:"domain-name"` -} - -func (rr *PX) Header() *RR_Header { return &rr.Hdr } -func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} } -func (rr *PX) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400) -} -func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 } - -type GPOS struct { - Hdr RR_Header - Longitude string - Latitude string - Altitude string -} - -func (rr *GPOS) Header() *RR_Header { return &rr.Hdr } -func (rr *GPOS) copy() RR { return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} } -func (rr *GPOS) len() int { - return rr.Hdr.len() + len(rr.Longitude) + len(rr.Latitude) + len(rr.Altitude) + 3 -} -func (rr *GPOS) String() string { - return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude -} - -type LOC struct { - Hdr RR_Header - Version uint8 - Size uint8 - HorizPre uint8 - VertPre uint8 - Latitude uint32 - Longitude uint32 - Altitude uint32 -} - -func (rr *LOC) Header() *RR_Header { return &rr.Hdr } -func (rr *LOC) len() int { return rr.Hdr.len() + 4 + 12 } -func (rr *LOC) copy() RR { - return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude} -} - -// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent -// format and returns a string in m (two decimals for the cm) -func cmToM(m, e uint8) string { - if e < 2 { - if e == 1 { - m *= 10 - } - - return fmt.Sprintf("0.%02d", m) - } - - s := fmt.Sprintf("%d", m) - for e > 2 { - s += "0" - e-- - } - return s -} - -// String returns a string version of a LOC -func (rr *LOC) String() string { - s := rr.Hdr.String() - - lat := rr.Latitude - ns := "N" - if lat > LOC_EQUATOR { - lat = lat - LOC_EQUATOR - } else { - ns = "S" - lat = LOC_EQUATOR - lat - } - h := lat / LOC_DEGREES - lat = lat % LOC_DEGREES - m := lat / LOC_HOURS - lat = lat % LOC_HOURS - s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lat) / 1000), ns) - - lon := rr.Longitude - ew := "E" - if lon > LOC_PRIMEMERIDIAN { - lon = lon - LOC_PRIMEMERIDIAN - } else { - ew = "W" - lon = LOC_PRIMEMERIDIAN - lon - } - h = lon / LOC_DEGREES - lon = lon % LOC_DEGREES - m = lon / LOC_HOURS - lon = lon % LOC_HOURS - s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew) - - var alt = float64(rr.Altitude) / 100 - alt -= LOC_ALTITUDEBASE - if rr.Altitude%100 != 0 { - s += fmt.Sprintf("%.2fm ", alt) - } else { - s += fmt.Sprintf("%.0fm ", alt) - } - - s += cmToM((rr.Size&0xf0)>>4, rr.Size&0x0f) + "m " - s += cmToM((rr.HorizPre&0xf0)>>4, rr.HorizPre&0x0f) + "m " - s += cmToM((rr.VertPre&0xf0)>>4, rr.VertPre&0x0f) + "m" - - return s -} - -// SIG is identical to RRSIG and nowadays only used for SIG(0), RFC2931. -type SIG struct { - RRSIG -} - -type RRSIG struct { - Hdr RR_Header - TypeCovered uint16 - Algorithm uint8 - Labels uint8 - OrigTtl uint32 - Expiration uint32 - Inception uint32 - KeyTag uint16 - SignerName string `dns:"domain-name"` - Signature string `dns:"base64"` -} - -func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr } -func (rr *RRSIG) copy() RR { - return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature} -} - -func (rr *RRSIG) String() string { - s := rr.Hdr.String() - s += Type(rr.TypeCovered).String() - s += " " + strconv.Itoa(int(rr.Algorithm)) + - " " + strconv.Itoa(int(rr.Labels)) + - " " + strconv.FormatInt(int64(rr.OrigTtl), 10) + - " " + TimeToString(rr.Expiration) + - " " + TimeToString(rr.Inception) + - " " + strconv.Itoa(int(rr.KeyTag)) + - " " + sprintName(rr.SignerName) + - " " + rr.Signature - return s -} - -func (rr *RRSIG) len() int { - return rr.Hdr.len() + len(rr.SignerName) + 1 + - base64.StdEncoding.DecodedLen(len(rr.Signature)) + 18 -} - -type NSEC struct { - Hdr RR_Header - NextDomain string `dns:"domain-name"` - TypeBitMap []uint16 `dns:"nsec"` -} - -func (rr *NSEC) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC) copy() RR { - cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap)) - copy(cp, rr.TypeBitMap) - return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, cp} -} - -func (rr *NSEC) String() string { - s := rr.Hdr.String() + sprintName(rr.NextDomain) - for i := 0; i < len(rr.TypeBitMap); i++ { - s += " " + Type(rr.TypeBitMap[i]).String() - } - return s -} - -func (rr *NSEC) len() int { - l := rr.Hdr.len() + len(rr.NextDomain) + 1 - lastwindow := uint32(2 ^ 32 + 1) - for _, t := range rr.TypeBitMap { - window := t / 256 - if uint32(window) != lastwindow { - l += 1 + 32 - } - lastwindow = uint32(window) - } - return l -} - -type DLV struct { - DS -} - -type CDS struct { - DS -} - -type DS struct { - Hdr RR_Header - KeyTag uint16 - Algorithm uint8 - DigestType uint8 - Digest string `dns:"hex"` -} - -func (rr *DS) Header() *RR_Header { return &rr.Hdr } -func (rr *DS) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 } -func (rr *DS) copy() RR { - return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} -} - -func (rr *DS) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) + - " " + strconv.Itoa(int(rr.Algorithm)) + - " " + strconv.Itoa(int(rr.DigestType)) + - " " + strings.ToUpper(rr.Digest) -} - -type KX struct { - Hdr RR_Header - Preference uint16 - Exchanger string `dns:"domain-name"` -} - -func (rr *KX) Header() *RR_Header { return &rr.Hdr } -func (rr *KX) len() int { return rr.Hdr.len() + 2 + len(rr.Exchanger) + 1 } -func (rr *KX) copy() RR { return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} } - -func (rr *KX) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + - " " + sprintName(rr.Exchanger) -} - -type TA struct { - Hdr RR_Header - KeyTag uint16 - Algorithm uint8 - DigestType uint8 - Digest string `dns:"hex"` -} - -func (rr *TA) Header() *RR_Header { return &rr.Hdr } -func (rr *TA) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 } -func (rr *TA) copy() RR { - return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} -} - -func (rr *TA) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) + - " " + strconv.Itoa(int(rr.Algorithm)) + - " " + strconv.Itoa(int(rr.DigestType)) + - " " + strings.ToUpper(rr.Digest) -} - -type TALINK struct { - Hdr RR_Header - PreviousName string `dns:"domain-name"` - NextName string `dns:"domain-name"` -} - -func (rr *TALINK) Header() *RR_Header { return &rr.Hdr } -func (rr *TALINK) copy() RR { return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} } -func (rr *TALINK) len() int { return rr.Hdr.len() + len(rr.PreviousName) + len(rr.NextName) + 2 } - -func (rr *TALINK) String() string { - return rr.Hdr.String() + - sprintName(rr.PreviousName) + " " + sprintName(rr.NextName) -} - -type SSHFP struct { - Hdr RR_Header - Algorithm uint8 - Type uint8 - FingerPrint string `dns:"hex"` -} - -func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr } -func (rr *SSHFP) len() int { return rr.Hdr.len() + 2 + len(rr.FingerPrint)/2 } -func (rr *SSHFP) copy() RR { - return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint} -} - -func (rr *SSHFP) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) + - " " + strconv.Itoa(int(rr.Type)) + - " " + strings.ToUpper(rr.FingerPrint) -} - -type IPSECKEY struct { - Hdr RR_Header - Precedence uint8 - // GatewayType: 1: A record, 2: AAAA record, 3: domainname. - // 0 is use for no type and GatewayName should be "." then. - GatewayType uint8 - Algorithm uint8 - // Gateway can be an A record, AAAA record or a domain name. - GatewayA net.IP `dns:"a"` - GatewayAAAA net.IP `dns:"aaaa"` - GatewayName string `dns:"domain-name"` - PublicKey string `dns:"base64"` -} - -func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *IPSECKEY) copy() RR { - return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.GatewayA, rr.GatewayAAAA, rr.GatewayName, rr.PublicKey} -} - -func (rr *IPSECKEY) String() string { - s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) + - " " + strconv.Itoa(int(rr.GatewayType)) + - " " + strconv.Itoa(int(rr.Algorithm)) - switch rr.GatewayType { - case 0: - fallthrough - case 3: - s += " " + rr.GatewayName - case 1: - s += " " + rr.GatewayA.String() - case 2: - s += " " + rr.GatewayAAAA.String() - default: - s += " ." - } - s += " " + rr.PublicKey - return s -} - -func (rr *IPSECKEY) len() int { - l := rr.Hdr.len() + 3 + 1 - switch rr.GatewayType { - default: - fallthrough - case 0: - fallthrough - case 3: - l += len(rr.GatewayName) - case 1: - l += 4 - case 2: - l += 16 - } - return l + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) -} - -type KEY struct { - DNSKEY -} - -type CDNSKEY struct { - DNSKEY -} - -type DNSKEY struct { - Hdr RR_Header - Flags uint16 - Protocol uint8 - Algorithm uint8 - PublicKey string `dns:"base64"` -} - -func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *DNSKEY) len() int { - return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) -} -func (rr *DNSKEY) copy() RR { - return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} -} - -func (rr *DNSKEY) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) + - " " + strconv.Itoa(int(rr.Protocol)) + - " " + strconv.Itoa(int(rr.Algorithm)) + - " " + rr.PublicKey -} - -type RKEY struct { - Hdr RR_Header - Flags uint16 - Protocol uint8 - Algorithm uint8 - PublicKey string `dns:"base64"` -} - -func (rr *RKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *RKEY) len() int { return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) } -func (rr *RKEY) copy() RR { - return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} -} - -func (rr *RKEY) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) + - " " + strconv.Itoa(int(rr.Protocol)) + - " " + strconv.Itoa(int(rr.Algorithm)) + - " " + rr.PublicKey -} - -type NSAP struct { - Hdr RR_Header - Length uint8 - Nsap string -} - -func (rr *NSAP) Header() *RR_Header { return &rr.Hdr } -func (rr *NSAP) copy() RR { return &NSAP{*rr.Hdr.copyHeader(), rr.Length, rr.Nsap} } -func (rr *NSAP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Length)) + " " + rr.Nsap } -func (rr *NSAP) len() int { return rr.Hdr.len() + 1 + len(rr.Nsap) + 1 } - -type NSAPPTR struct { - Hdr RR_Header - Ptr string `dns:"domain-name"` -} - -func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr } -func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} } -func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) } -func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) } - -type NSEC3 struct { - Hdr RR_Header - Hash uint8 - Flags uint8 - Iterations uint16 - SaltLength uint8 - Salt string `dns:"size-hex"` - HashLength uint8 - NextDomain string `dns:"size-base32"` - TypeBitMap []uint16 `dns:"nsec"` -} - -func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC3) copy() RR { - cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap)) - copy(cp, rr.TypeBitMap) - return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, cp} -} - -func (rr *NSEC3) String() string { - s := rr.Hdr.String() - s += strconv.Itoa(int(rr.Hash)) + - " " + strconv.Itoa(int(rr.Flags)) + - " " + strconv.Itoa(int(rr.Iterations)) + - " " + saltToString(rr.Salt) + - " " + rr.NextDomain - for i := 0; i < len(rr.TypeBitMap); i++ { - s += " " + Type(rr.TypeBitMap[i]).String() - } - return s -} - -func (rr *NSEC3) len() int { - l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1 - lastwindow := uint32(2 ^ 32 + 1) - for _, t := range rr.TypeBitMap { - window := t / 256 - if uint32(window) != lastwindow { - l += 1 + 32 - } - lastwindow = uint32(window) - } - return l -} - -type NSEC3PARAM struct { - Hdr RR_Header - Hash uint8 - Flags uint8 - Iterations uint16 - SaltLength uint8 - Salt string `dns:"hex"` -} - -func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC3PARAM) len() int { return rr.Hdr.len() + 2 + 4 + 1 + len(rr.Salt)/2 } -func (rr *NSEC3PARAM) copy() RR { - return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt} -} - -func (rr *NSEC3PARAM) String() string { - s := rr.Hdr.String() - s += strconv.Itoa(int(rr.Hash)) + - " " + strconv.Itoa(int(rr.Flags)) + - " " + strconv.Itoa(int(rr.Iterations)) + - " " + saltToString(rr.Salt) - return s -} - -type TKEY struct { - Hdr RR_Header - Algorithm string `dns:"domain-name"` - Inception uint32 - Expiration uint32 - Mode uint16 - Error uint16 - KeySize uint16 - Key string - OtherLen uint16 - OtherData string -} - -func (rr *TKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *TKEY) copy() RR { - return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData} -} - -func (rr *TKEY) String() string { - // It has no presentation format - return "" -} - -func (rr *TKEY) len() int { - return rr.Hdr.len() + len(rr.Algorithm) + 1 + 4 + 4 + 6 + - len(rr.Key) + 2 + len(rr.OtherData) -} - -// RFC3597 represents an unknown/generic RR. -type RFC3597 struct { - Hdr RR_Header - Rdata string `dns:"hex"` -} - -func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr } -func (rr *RFC3597) copy() RR { return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} } -func (rr *RFC3597) len() int { return rr.Hdr.len() + len(rr.Rdata)/2 + 2 } - -func (rr *RFC3597) String() string { - // Let's call it a hack - s := rfc3597Header(rr.Hdr) - - s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata - return s -} - -func rfc3597Header(h RR_Header) string { - var s string - - s += sprintName(h.Name) + "\t" - s += strconv.FormatInt(int64(h.Ttl), 10) + "\t" - s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t" - s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t" - return s -} - -type URI struct { - Hdr RR_Header - Priority uint16 - Weight uint16 - Target []string `dns:"txt"` -} - -func (rr *URI) Header() *RR_Header { return &rr.Hdr } -func (rr *URI) copy() RR { - cp := make([]string, len(rr.Target), cap(rr.Target)) - copy(cp, rr.Target) - return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, cp} -} - -func (rr *URI) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) + - " " + strconv.Itoa(int(rr.Weight)) + sprintTxt(rr.Target) -} - -func (rr *URI) len() int { - l := rr.Hdr.len() + 4 - for _, t := range rr.Target { - l += len(t) + 1 - } - return l -} - -type DHCID struct { - Hdr RR_Header - Digest string `dns:"base64"` -} - -func (rr *DHCID) Header() *RR_Header { return &rr.Hdr } -func (rr *DHCID) copy() RR { return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} } -func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest } -func (rr *DHCID) len() int { return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.Digest)) } - -type TLSA struct { - Hdr RR_Header - Usage uint8 - Selector uint8 - MatchingType uint8 - Certificate string `dns:"hex"` -} - -func (rr *TLSA) Header() *RR_Header { return &rr.Hdr } -func (rr *TLSA) len() int { return rr.Hdr.len() + 3 + len(rr.Certificate)/2 } - -func (rr *TLSA) copy() RR { - return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} -} - -func (rr *TLSA) String() string { - return rr.Hdr.String() + - strconv.Itoa(int(rr.Usage)) + - " " + strconv.Itoa(int(rr.Selector)) + - " " + strconv.Itoa(int(rr.MatchingType)) + - " " + rr.Certificate -} - -type HIP struct { - Hdr RR_Header - HitLength uint8 - PublicKeyAlgorithm uint8 - PublicKeyLength uint16 - Hit string `dns:"hex"` - PublicKey string `dns:"base64"` - RendezvousServers []string `dns:"domain-name"` -} - -func (rr *HIP) Header() *RR_Header { return &rr.Hdr } -func (rr *HIP) copy() RR { - cp := make([]string, len(rr.RendezvousServers), cap(rr.RendezvousServers)) - copy(cp, rr.RendezvousServers) - return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, cp} -} - -func (rr *HIP) String() string { - s := rr.Hdr.String() + - strconv.Itoa(int(rr.PublicKeyAlgorithm)) + - " " + rr.Hit + - " " + rr.PublicKey - for _, d := range rr.RendezvousServers { - s += " " + sprintName(d) - } - return s -} - -func (rr *HIP) len() int { - l := rr.Hdr.len() + 4 + - len(rr.Hit)/2 + - base64.StdEncoding.DecodedLen(len(rr.PublicKey)) - for _, d := range rr.RendezvousServers { - l += len(d) + 1 - } - return l -} - -type NINFO struct { - Hdr RR_Header - ZSData []string `dns:"txt"` -} - -func (rr *NINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *NINFO) copy() RR { - cp := make([]string, len(rr.ZSData), cap(rr.ZSData)) - copy(cp, rr.ZSData) - return &NINFO{*rr.Hdr.copyHeader(), cp} -} - -func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) } - -func (rr *NINFO) len() int { - l := rr.Hdr.len() - for _, t := range rr.ZSData { - l += len(t) + 1 - } - return l -} - -type WKS struct { - Hdr RR_Header - Address net.IP `dns:"a"` - Protocol uint8 - BitMap []uint16 `dns:"wks"` -} - -func (rr *WKS) Header() *RR_Header { return &rr.Hdr } -func (rr *WKS) len() int { return rr.Hdr.len() + net.IPv4len + 1 } - -func (rr *WKS) copy() RR { - cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap)) - copy(cp, rr.BitMap) - return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp} -} - -func (rr *WKS) String() (s string) { - s = rr.Hdr.String() - if rr.Address != nil { - s += rr.Address.String() - } - // TODO(miek): missing protocol here, see /etc/protocols - for i := 0; i < len(rr.BitMap); i++ { - // should lookup the port - s += " " + strconv.Itoa(int(rr.BitMap[i])) - } - return s -} - -type NID struct { - Hdr RR_Header - Preference uint16 - NodeID uint64 -} - -func (rr *NID) Header() *RR_Header { return &rr.Hdr } -func (rr *NID) copy() RR { return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} } -func (rr *NID) len() int { return rr.Hdr.len() + 2 + 8 } - -func (rr *NID) String() string { - s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) - node := fmt.Sprintf("%0.16x", rr.NodeID) - s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16] - return s -} - -type L32 struct { - Hdr RR_Header - Preference uint16 - Locator32 net.IP `dns:"a"` -} - -func (rr *L32) Header() *RR_Header { return &rr.Hdr } -func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} } -func (rr *L32) len() int { return rr.Hdr.len() + net.IPv4len } - -func (rr *L32) String() string { - if rr.Locator32 == nil { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) - } - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + - " " + rr.Locator32.String() -} - -type L64 struct { - Hdr RR_Header - Preference uint16 - Locator64 uint64 -} - -func (rr *L64) Header() *RR_Header { return &rr.Hdr } -func (rr *L64) copy() RR { return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} } -func (rr *L64) len() int { return rr.Hdr.len() + 2 + 8 } - -func (rr *L64) String() string { - s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) - node := fmt.Sprintf("%0.16X", rr.Locator64) - s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16] - return s -} - -type LP struct { - Hdr RR_Header - Preference uint16 - Fqdn string `dns:"domain-name"` -} - -func (rr *LP) Header() *RR_Header { return &rr.Hdr } -func (rr *LP) copy() RR { return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} } -func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 } - -func (rr *LP) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn) -} - -type EUI48 struct { - Hdr RR_Header - Address uint64 `dns:"uint48"` -} - -func (rr *EUI48) Header() *RR_Header { return &rr.Hdr } -func (rr *EUI48) copy() RR { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} } -func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) } -func (rr *EUI48) len() int { return rr.Hdr.len() + 6 } - -type EUI64 struct { - Hdr RR_Header - Address uint64 -} - -func (rr *EUI64) Header() *RR_Header { return &rr.Hdr } -func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} } -func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) } -func (rr *EUI64) len() int { return rr.Hdr.len() + 8 } - -// Support in incomplete - just handle it as unknown record -/* -type CAA struct { - Hdr RR_Header - Flag uint8 - Tag string - Value string `dns:"octet"` -} - -func (rr *CAA) Header() *RR_Header { return &rr.Hdr } -func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} } -func (rr *CAA) len() int { return rr.Hdr.len() + 1 + len(rr.Tag) + 1 + len(rr.Value) } - -func (rr *CAA) String() string { - s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Flag), 10) + " " + rr.Tag - s += strconv.QuoteToASCII(rr.Value) - return s -} -*/ - -type UID struct { - Hdr RR_Header - Uid uint32 -} - -func (rr *UID) Header() *RR_Header { return &rr.Hdr } -func (rr *UID) copy() RR { return &UID{*rr.Hdr.copyHeader(), rr.Uid} } -func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) } -func (rr *UID) len() int { return rr.Hdr.len() + 4 } - -type GID struct { - Hdr RR_Header - Gid uint32 -} - -func (rr *GID) Header() *RR_Header { return &rr.Hdr } -func (rr *GID) copy() RR { return &GID{*rr.Hdr.copyHeader(), rr.Gid} } -func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) } -func (rr *GID) len() int { return rr.Hdr.len() + 4 } - -type UINFO struct { - Hdr RR_Header - Uinfo string -} - -func (rr *UINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} } -func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) } -func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 } - -type EID struct { - Hdr RR_Header - Endpoint string `dns:"hex"` -} - -func (rr *EID) Header() *RR_Header { return &rr.Hdr } -func (rr *EID) copy() RR { return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} } -func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) } -func (rr *EID) len() int { return rr.Hdr.len() + len(rr.Endpoint)/2 } - -type NIMLOC struct { - Hdr RR_Header - Locator string `dns:"hex"` -} - -func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr } -func (rr *NIMLOC) copy() RR { return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} } -func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) } -func (rr *NIMLOC) len() int { return rr.Hdr.len() + len(rr.Locator)/2 } - -type OPENPGPKEY struct { - Hdr RR_Header - PublicKey string `dns:"base64"` -} - -func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *OPENPGPKEY) copy() RR { return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} } -func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey } -func (rr *OPENPGPKEY) len() int { - return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) -} - -// TimeToString translates the RRSIG's incep. and expir. times to the -// string representation used when printing the record. -// It takes serial arithmetic (RFC 1982) into account. -func TimeToString(t uint32) string { - mod := ((int64(t) - time.Now().Unix()) / year68) - 1 - if mod < 0 { - mod = 0 - } - ti := time.Unix(int64(t)-(mod*year68), 0).UTC() - return ti.Format("20060102150405") -} - -// StringToTime translates the RRSIG's incep. and expir. times from -// string values like "20110403154150" to an 32 bit integer. -// It takes serial arithmetic (RFC 1982) into account. -func StringToTime(s string) (uint32, error) { - t, e := time.Parse("20060102150405", s) - if e != nil { - return 0, e - } - mod := (t.Unix() / year68) - 1 - if mod < 0 { - mod = 0 - } - return uint32(t.Unix() - (mod * year68)), nil -} - -// saltToString converts a NSECX salt to uppercase and -// returns "-" when it is empty -func saltToString(s string) string { - if len(s) == 0 { - return "-" - } - return strings.ToUpper(s) -} - -func euiToString(eui uint64, bits int) (hex string) { - switch bits { - case 64: - hex = fmt.Sprintf("%16.16x", eui) - hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] + - "-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16] - case 48: - hex = fmt.Sprintf("%12.12x", eui) - hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] + - "-" + hex[8:10] + "-" + hex[10:12] - } - return -} - -// copyIP returns a copy of ip. -func copyIP(ip net.IP) net.IP { - p := make(net.IP, len(ip)) - copy(p, ip) - return p -} - -// Map of constructors for each RR type. -var typeToRR = map[uint16]func() RR{ - TypeA: func() RR { return new(A) }, - TypeAAAA: func() RR { return new(AAAA) }, - TypeAFSDB: func() RR { return new(AFSDB) }, - // TypeCAA: func() RR { return new(CAA) }, - TypeCDS: func() RR { return new(CDS) }, - TypeCERT: func() RR { return new(CERT) }, - TypeCNAME: func() RR { return new(CNAME) }, - TypeDHCID: func() RR { return new(DHCID) }, - TypeDLV: func() RR { return new(DLV) }, - TypeDNAME: func() RR { return new(DNAME) }, - TypeKEY: func() RR { return new(KEY) }, - TypeDNSKEY: func() RR { return new(DNSKEY) }, - TypeDS: func() RR { return new(DS) }, - TypeEUI48: func() RR { return new(EUI48) }, - TypeEUI64: func() RR { return new(EUI64) }, - TypeGID: func() RR { return new(GID) }, - TypeGPOS: func() RR { return new(GPOS) }, - TypeEID: func() RR { return new(EID) }, - TypeHINFO: func() RR { return new(HINFO) }, - TypeHIP: func() RR { return new(HIP) }, - TypeIPSECKEY: func() RR { return new(IPSECKEY) }, - TypeKX: func() RR { return new(KX) }, - TypeL32: func() RR { return new(L32) }, - TypeL64: func() RR { return new(L64) }, - TypeLOC: func() RR { return new(LOC) }, - TypeLP: func() RR { return new(LP) }, - TypeMB: func() RR { return new(MB) }, - TypeMD: func() RR { return new(MD) }, - TypeMF: func() RR { return new(MF) }, - TypeMG: func() RR { return new(MG) }, - TypeMINFO: func() RR { return new(MINFO) }, - TypeMR: func() RR { return new(MR) }, - TypeMX: func() RR { return new(MX) }, - TypeNAPTR: func() RR { return new(NAPTR) }, - TypeNID: func() RR { return new(NID) }, - TypeNINFO: func() RR { return new(NINFO) }, - TypeNIMLOC: func() RR { return new(NIMLOC) }, - TypeNS: func() RR { return new(NS) }, - TypeNSAP: func() RR { return new(NSAP) }, - TypeNSAPPTR: func() RR { return new(NSAPPTR) }, - TypeNSEC3: func() RR { return new(NSEC3) }, - TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) }, - TypeNSEC: func() RR { return new(NSEC) }, - TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) }, - TypeOPT: func() RR { return new(OPT) }, - TypePTR: func() RR { return new(PTR) }, - TypeRKEY: func() RR { return new(RKEY) }, - TypeRP: func() RR { return new(RP) }, - TypePX: func() RR { return new(PX) }, - TypeSIG: func() RR { return new(SIG) }, - TypeRRSIG: func() RR { return new(RRSIG) }, - TypeRT: func() RR { return new(RT) }, - TypeSOA: func() RR { return new(SOA) }, - TypeSPF: func() RR { return new(SPF) }, - TypeSRV: func() RR { return new(SRV) }, - TypeSSHFP: func() RR { return new(SSHFP) }, - TypeTA: func() RR { return new(TA) }, - TypeTALINK: func() RR { return new(TALINK) }, - TypeTKEY: func() RR { return new(TKEY) }, - TypeTLSA: func() RR { return new(TLSA) }, - TypeTSIG: func() RR { return new(TSIG) }, - TypeTXT: func() RR { return new(TXT) }, - TypeUID: func() RR { return new(UID) }, - TypeUINFO: func() RR { return new(UINFO) }, - TypeURI: func() RR { return new(URI) }, - TypeWKS: func() RR { return new(WKS) }, - TypeX25: func() RR { return new(X25) }, -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/types_test.go b/Godeps/_workspace/src/github.com/miekg/dns/types_test.go deleted file mode 100644 index 118612946..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/types_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package dns - -import ( - "testing" -) - -func TestCmToM(t *testing.T) { - s := cmToM(0, 0) - if s != "0.00" { - t.Error("0, 0") - } - - s = cmToM(1, 0) - if s != "0.01" { - t.Error("1, 0") - } - - s = cmToM(3, 1) - if s != "0.30" { - t.Error("3, 1") - } - - s = cmToM(4, 2) - if s != "4" { - t.Error("4, 2") - } - - s = cmToM(5, 3) - if s != "50" { - t.Error("5, 3") - } - - s = cmToM(7, 5) - if s != "7000" { - t.Error("7, 5") - } - - s = cmToM(9, 9) - if s != "90000000" { - t.Error("9, 9") - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/udp.go b/Godeps/_workspace/src/github.com/miekg/dns/udp.go deleted file mode 100644 index 5430e84ec..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/udp.go +++ /dev/null @@ -1,55 +0,0 @@ -// +build !windows - -package dns - -import ( - "net" - "syscall" -) - -type SessionUDP struct { - raddr *net.UDPAddr - context []byte -} - -func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } - -// setUDPSocketOptions sets the UDP socket options. -// This function is implemented on a per platform basis. See udp_*.go for more details -func setUDPSocketOptions(conn *net.UDPConn) error { - sa, err := getUDPSocketName(conn) - if err != nil { - return err - } - switch sa.(type) { - case *syscall.SockaddrInet6: - v6only, err := getUDPSocketOptions6Only(conn) - if err != nil { - return err - } - setUDPSocketOptions6(conn) - if !v6only { - setUDPSocketOptions4(conn) - } - case *syscall.SockaddrInet4: - setUDPSocketOptions4(conn) - } - return nil -} - -// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a -// net.UDPAddr. -func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { - oob := make([]byte, 40) - n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) - if err != nil { - return n, nil, err - } - return n, &SessionUDP{raddr, oob[:oobn]}, err -} - -// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. -func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { - n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) - return n, err -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go b/Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go deleted file mode 100644 index 7a107857e..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go +++ /dev/null @@ -1,63 +0,0 @@ -// +build linux - -package dns - -// See: -// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and -// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/ -// -// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing -// interface, this might not always be the correct one. This code will make sure the egress -// packet's interface matched the ingress' one. - -import ( - "net" - "syscall" -) - -// setUDPSocketOptions4 prepares the v4 socket for sessions. -func setUDPSocketOptions4(conn *net.UDPConn) error { - file, err := conn.File() - if err != nil { - return err - } - if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil { - return err - } - return nil -} - -// setUDPSocketOptions6 prepares the v6 socket for sessions. -func setUDPSocketOptions6(conn *net.UDPConn) error { - file, err := conn.File() - if err != nil { - return err - } - if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil { - return err - } - return nil -} - -// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined -// (dualstack). -func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { - file, err := conn.File() - if err != nil { - return false, err - } - // dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections - v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY) - if err != nil { - return false, err - } - return v6only == 1, nil -} - -func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { - file, err := conn.File() - if err != nil { - return nil, err - } - return syscall.Getsockname(int(file.Fd())) -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/udp_other.go b/Godeps/_workspace/src/github.com/miekg/dns/udp_other.go deleted file mode 100644 index c38dd3e7f..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/udp_other.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !linux - -package dns - -import ( - "net" - "syscall" -) - -// These do nothing. See udp_linux.go for an example of how to implement this. - -// We tried to adhire to some kind of naming scheme. - -func setUDPSocketOptions4(conn *net.UDPConn) error { return nil } -func setUDPSocketOptions6(conn *net.UDPConn) error { return nil } -func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil } -func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil } diff --git a/Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go b/Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go deleted file mode 100644 index 2ce4b3300..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -// +build windows - -package dns - -import "net" - -type SessionUDP struct { - raddr *net.UDPAddr -} - -// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a -// net.UDPAddr. -func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { - n, raddr, err := conn.ReadFrom(b) - if err != nil { - return n, nil, err - } - session := &SessionUDP{raddr.(*net.UDPAddr)} - return n, session, err -} - -// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. -func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { - n, err := conn.WriteTo(b, session.raddr) - return n, err -} - -func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } - -// setUDPSocketOptions sets the UDP socket options. -// This function is implemented on a per platform basis. See udp_*.go for more details -func setUDPSocketOptions(conn *net.UDPConn) error { - return nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/update.go b/Godeps/_workspace/src/github.com/miekg/dns/update.go deleted file mode 100644 index 3539987cc..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/update.go +++ /dev/null @@ -1,94 +0,0 @@ -package dns - -// NameUsed sets the RRs in the prereq section to -// "Name is in use" RRs. RFC 2136 section 2.4.4. -func (u *Msg) NameUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} - } -} - -// NameNotUsed sets the RRs in the prereq section to -// "Name is in not use" RRs. RFC 2136 section 2.4.5. -func (u *Msg) NameNotUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}} - } -} - -// Used sets the RRs in the prereq section to -// "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2. -func (u *Msg) Used(rr []RR) { - if len(u.Question) == 0 { - panic("dns: empty question section") - } - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = u.Question[0].Qclass - } -} - -// RRsetUsed sets the RRs in the prereq section to -// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1. -func (u *Msg) RRsetUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = ClassANY - u.Answer[i].Header().Ttl = 0 - u.Answer[i].Header().Rdlength = 0 - } -} - -// RRsetNotUsed sets the RRs in the prereq section to -// "RRset does not exist" RRs. RFC 2136 section 2.4.3. -func (u *Msg) RRsetNotUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = ClassNONE - u.Answer[i].Header().Rdlength = 0 - u.Answer[i].Header().Ttl = 0 - } -} - -// Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1. -func (u *Msg) Insert(rr []RR) { - if len(u.Question) == 0 { - panic("dns: empty question section") - } - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = r - u.Ns[i].Header().Class = u.Question[0].Qclass - } -} - -// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2. -func (u *Msg) RemoveRRset(rr []RR) { - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}} - } -} - -// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3 -func (u *Msg) RemoveName(rr []RR) { - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} - } -} - -// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4 -func (u *Msg) Remove(rr []RR) { - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = r - u.Ns[i].Header().Class = ClassNONE - u.Ns[i].Header().Ttl = 0 - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/update_test.go b/Godeps/_workspace/src/github.com/miekg/dns/update_test.go deleted file mode 100644 index 0c6d1e235..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/update_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package dns - -import ( - "bytes" - "testing" -) - -func TestDynamicUpdateParsing(t *testing.T) { - prefix := "example.com. IN " - for _, typ := range TypeToString { - if typ == "CAA" || typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" || - typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" { - continue - } - r, err := NewRR(prefix + typ) - if err != nil { - t.Errorf("failure to parse: %s %s: %v", prefix, typ, err) - } else { - t.Logf("parsed: %s", r.String()) - } - } -} - -func TestDynamicUpdateUnpack(t *testing.T) { - // From https://github.com/miekg/dns/issues/150#issuecomment-62296803 - // It should be an update message for the zone "example.", - // deleting the A RRset "example." and then adding an A record at "example.". - // class ANY, TYPE A - buf := []byte{171, 68, 40, 0, 0, 1, 0, 0, 0, 2, 0, 0, 7, 101, 120, 97, 109, 112, 108, 101, 0, 0, 6, 0, 1, 192, 12, 0, 1, 0, 255, 0, 0, 0, 0, 0, 0, 192, 12, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 127, 0, 0, 1} - msg := new(Msg) - err := msg.Unpack(buf) - if err != nil { - t.Errorf("failed to unpack: %v\n%s", err, msg.String()) - } -} - -func TestDynamicUpdateZeroRdataUnpack(t *testing.T) { - m := new(Msg) - rr := &RR_Header{Name: ".", Rrtype: 0, Class: 1, Ttl: ^uint32(0), Rdlength: 0} - m.Answer = []RR{rr, rr, rr, rr, rr} - m.Ns = m.Answer - for n, s := range TypeToString { - rr.Rrtype = n - bytes, err := m.Pack() - if err != nil { - t.Errorf("failed to pack %s: %v", s, err) - continue - } - if err := new(Msg).Unpack(bytes); err != nil { - t.Errorf("failed to unpack %s: %v", s, err) - } - } -} - -func TestRemoveRRset(t *testing.T) { - // Should add a zero data RR in Class ANY with a TTL of 0 - // for each set mentioned in the RRs provided to it. - rr, err := NewRR(". 100 IN A 127.0.0.1") - if err != nil { - t.Fatalf("Error constructing RR: %v", err) - } - m := new(Msg) - m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}} - expectstr := m.String() - expect, err := m.Pack() - if err != nil { - t.Fatalf("Error packing expected msg: %v", err) - } - - m.Ns = nil - m.RemoveRRset([]RR{rr}) - actual, err := m.Pack() - if err != nil { - t.Fatalf("Error packing actual msg: %v", err) - } - if !bytes.Equal(actual, expect) { - tmp := new(Msg) - if err := tmp.Unpack(actual); err != nil { - t.Fatalf("Error unpacking actual msg: %v", err) - } - t.Errorf("Expected msg:\n%s", expectstr) - t.Errorf("Actual msg:\n%v", tmp) - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/xfr.go b/Godeps/_workspace/src/github.com/miekg/dns/xfr.go deleted file mode 100644 index 3d2b3e6a4..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/xfr.go +++ /dev/null @@ -1,233 +0,0 @@ -package dns - -import ( - "time" -) - -// Envelope is used when doing a zone transfer with a remote server. -type Envelope struct { - RR []RR // The set of RRs in the answer section of the xfr reply message. - Error error // If something went wrong, this contains the error. -} - -// A Transfer defines parameters that are used during a zone transfer. -type Transfer struct { - *Conn - DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds - ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - TsigSecret map[string]string // Secret(s) for Tsig map[], zonename must be fully qualified - tsigTimersOnly bool -} - -// Think we need to away to stop the transfer - -// In performs an incoming transfer with the server in a. -func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) { - timeout := dnsTimeout - if t.DialTimeout != 0 { - timeout = t.DialTimeout - } - t.Conn, err = DialTimeout("tcp", a, timeout) - if err != nil { - return nil, err - } - if err := t.WriteMsg(q); err != nil { - return nil, err - } - env = make(chan *Envelope) - go func() { - if q.Question[0].Qtype == TypeAXFR { - go t.inAxfr(q.Id, env) - return - } - if q.Question[0].Qtype == TypeIXFR { - go t.inIxfr(q.Id, env) - return - } - }() - return env, nil -} - -func (t *Transfer) inAxfr(id uint16, c chan *Envelope) { - first := true - defer t.Close() - defer close(c) - timeout := dnsTimeout - if t.ReadTimeout != 0 { - timeout = t.ReadTimeout - } - for { - t.Conn.SetReadDeadline(time.Now().Add(timeout)) - in, err := t.ReadMsg() - if err != nil { - c <- &Envelope{nil, err} - return - } - if id != in.Id { - c <- &Envelope{in.Answer, ErrId} - return - } - if first { - if !isSOAFirst(in) { - c <- &Envelope{in.Answer, ErrSoa} - return - } - first = !first - // only one answer that is SOA, receive more - if len(in.Answer) == 1 { - t.tsigTimersOnly = true - c <- &Envelope{in.Answer, nil} - continue - } - } - - if !first { - t.tsigTimersOnly = true // Subsequent envelopes use this. - if isSOALast(in) { - c <- &Envelope{in.Answer, nil} - return - } - c <- &Envelope{in.Answer, nil} - } - } - panic("dns: not reached") -} - -func (t *Transfer) inIxfr(id uint16, c chan *Envelope) { - serial := uint32(0) // The first serial seen is the current server serial - first := true - defer t.Close() - defer close(c) - timeout := dnsTimeout - if t.ReadTimeout != 0 { - timeout = t.ReadTimeout - } - for { - t.SetReadDeadline(time.Now().Add(timeout)) - in, err := t.ReadMsg() - if err != nil { - c <- &Envelope{in.Answer, err} - return - } - if id != in.Id { - c <- &Envelope{in.Answer, ErrId} - return - } - if first { - // A single SOA RR signals "no changes" - if len(in.Answer) == 1 && isSOAFirst(in) { - c <- &Envelope{in.Answer, nil} - return - } - - // Check if the returned answer is ok - if !isSOAFirst(in) { - c <- &Envelope{in.Answer, ErrSoa} - return - } - // This serial is important - serial = in.Answer[0].(*SOA).Serial - first = !first - } - - // Now we need to check each message for SOA records, to see what we need to do - if !first { - t.tsigTimersOnly = true - // If the last record in the IXFR contains the servers' SOA, we should quit - if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok { - if v.Serial == serial { - c <- &Envelope{in.Answer, nil} - return - } - } - c <- &Envelope{in.Answer, nil} - } - } -} - -// Out performs an outgoing transfer with the client connecting in w. -// Basic use pattern: -// -// ch := make(chan *dns.Envelope) -// tr := new(dns.Transfer) -// tr.Out(w, r, ch) -// c <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}} -// close(ch) -// w.Hijack() -// // w.Close() // Client closes connection -// -// The server is responsible for sending the correct sequence of RRs through the -// channel ch. -func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error { - for x := range ch { - r := new(Msg) - // Compress? - r.SetReply(q) - r.Authoritative = true - // assume it fits TODO(miek): fix - r.Answer = append(r.Answer, x.RR...) - if err := w.WriteMsg(r); err != nil { - return err - } - } - w.TsigTimersOnly(true) - return nil -} - -// ReadMsg reads a message from the transfer connection t. -func (t *Transfer) ReadMsg() (*Msg, error) { - m := new(Msg) - p := make([]byte, MaxMsgSize) - n, err := t.Read(p) - if err != nil && n == 0 { - return nil, err - } - p = p[:n] - if err := m.Unpack(p); err != nil { - return nil, err - } - if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil { - if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok { - return m, ErrSecret - } - // Need to work on the original message p, as that was used to calculate the tsig. - err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly) - t.tsigRequestMAC = ts.MAC - } - return m, err -} - -// WriteMsg writes a message through the transfer connection t. -func (t *Transfer) WriteMsg(m *Msg) (err error) { - var out []byte - if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil { - if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok { - return ErrSecret - } - out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly) - } else { - out, err = m.Pack() - } - if err != nil { - return err - } - if _, err = t.Write(out); err != nil { - return err - } - return nil -} - -func isSOAFirst(in *Msg) bool { - if len(in.Answer) > 0 { - return in.Answer[0].Header().Rrtype == TypeSOA - } - return false -} - -func isSOALast(in *Msg) bool { - if len(in.Answer) > 0 { - return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA - } - return false -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go b/Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go deleted file mode 100644 index d52d84c6a..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package dns - -import ( - "net" - "testing" - "time" -) - -func getIP(s string) string { - a, err := net.LookupAddr(s) - if err != nil { - return "" - } - return a[0] -} - -// flaky, need to setup local server and test from -// that. -func testClientAXFR(t *testing.T) { - if testing.Short() { - return - } - m := new(Msg) - m.SetAxfr("miek.nl.") - - server := getIP("linode.atoom.net") - - tr := new(Transfer) - - if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil { - t.Fatal("failed to setup axfr: ", err) - } else { - for ex := range a { - if ex.Error != nil { - t.Errorf("error %v", ex.Error) - break - } - for _, rr := range ex.RR { - t.Log(rr.String()) - } - } - } -} - -// fails. -func testClientAXFRMultipleEnvelopes(t *testing.T) { - if testing.Short() { - return - } - m := new(Msg) - m.SetAxfr("nlnetlabs.nl.") - - server := getIP("open.nlnetlabs.nl.") - - tr := new(Transfer) - if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil { - t.Fatalf("Failed to setup axfr %v for server: %v", err, server) - } else { - for ex := range a { - if ex.Error != nil { - t.Errorf("Error %v", ex.Error) - break - } - } - } -} - -func testClientTsigAXFR(t *testing.T) { - if testing.Short() { - return - } - m := new(Msg) - m.SetAxfr("example.nl.") - m.SetTsig("axfr.", HmacMD5, 300, time.Now().Unix()) - - tr := new(Transfer) - tr.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} - - if a, err := tr.In(m, "176.58.119.54:53"); err != nil { - t.Fatal("failed to setup axfr: ", err) - } else { - for ex := range a { - if ex.Error != nil { - t.Errorf("error %v", ex.Error) - break - } - for _, rr := range ex.RR { - t.Log(rr.String()) - } - } - } -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go b/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go deleted file mode 100644 index ae9253157..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go +++ /dev/null @@ -1,158 +0,0 @@ -package dns - -import ( - "bytes" - "fmt" - "strconv" - "strings" -) - -// Parse the $GENERATE statement as used in BIND9 zones. -// See http://www.zytrax.com/books/dns/ch8/generate.html for instance. -// We are called after '$GENERATE '. After which we expect: -// * the range (12-24/2) -// * lhs (ownername) -// * [[ttl][class]] -// * type -// * rhs (rdata) -// But we are lazy here, only the range is parsed *all* occurences -// of $ after that are interpreted. -// Any error are returned as a string value, the empty string signals -// "no error". -func generate(l lex, c chan lex, t chan *Token, o string) string { - step := 1 - if i := strings.IndexAny(l.token, "/"); i != -1 { - if i+1 == len(l.token) { - return "bad step in $GENERATE range" - } - if s, e := strconv.Atoi(l.token[i+1:]); e == nil { - if s < 0 { - return "bad step in $GENERATE range" - } - step = s - } else { - return "bad step in $GENERATE range" - } - l.token = l.token[:i] - } - sx := strings.SplitN(l.token, "-", 2) - if len(sx) != 2 { - return "bad start-stop in $GENERATE range" - } - start, err := strconv.Atoi(sx[0]) - if err != nil { - return "bad start in $GENERATE range" - } - end, err := strconv.Atoi(sx[1]) - if err != nil { - return "bad stop in $GENERATE range" - } - if end < 0 || start < 0 || end < start { - return "bad range in $GENERATE range" - } - - <-c // _BLANK - // Create a complete new string, which we then parse again. - s := "" -BuildRR: - l = <-c - if l.value != zNewline && l.value != zEOF { - s += l.token - goto BuildRR - } - for i := start; i <= end; i += step { - var ( - escape bool - dom bytes.Buffer - mod string - err string - offset int - ) - - for j := 0; j < len(s); j++ { // No 'range' because we need to jump around - switch s[j] { - case '\\': - if escape { - dom.WriteByte('\\') - escape = false - continue - } - escape = true - case '$': - mod = "%d" - offset = 0 - if escape { - dom.WriteByte('$') - escape = false - continue - } - escape = false - if j+1 >= len(s) { // End of the string - dom.WriteString(fmt.Sprintf(mod, i+offset)) - continue - } else { - if s[j+1] == '$' { - dom.WriteByte('$') - j++ - continue - } - } - // Search for { and } - if s[j+1] == '{' { // Modifier block - sep := strings.Index(s[j+2:], "}") - if sep == -1 { - return "bad modifier in $GENERATE" - } - mod, offset, err = modToPrintf(s[j+2 : j+2+sep]) - if err != "" { - return err - } - j += 2 + sep // Jump to it - } - dom.WriteString(fmt.Sprintf(mod, i+offset)) - default: - if escape { // Pretty useless here - escape = false - continue - } - dom.WriteByte(s[j]) - } - } - // Re-parse the RR and send it on the current channel t - rx, e := NewRR("$ORIGIN " + o + "\n" + dom.String()) - if e != nil { - return e.(*ParseError).err - } - t <- &Token{RR: rx} - // Its more efficient to first built the rrlist and then parse it in - // one go! But is this a problem? - } - return "" -} - -// Convert a $GENERATE modifier 0,0,d to something Printf can deal with. -func modToPrintf(s string) (string, int, string) { - xs := strings.SplitN(s, ",", 3) - if len(xs) != 3 { - return "", 0, "bad modifier in $GENERATE" - } - // xs[0] is offset, xs[1] is width, xs[2] is base - if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" { - return "", 0, "bad base in $GENERATE" - } - offset, err := strconv.Atoi(xs[0]) - if err != nil { - return "", 0, "bad offset in $GENERATE" - } - width, err := strconv.Atoi(xs[1]) - if err != nil { - return "", offset, "bad width in $GENERATE" - } - switch { - case width < 0: - return "", offset, "bad width in $GENERATE" - case width == 0: - return "%" + xs[1] + xs[2], offset, "" - } - return "%0" + xs[1] + xs[2], offset, "" -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zscan.go b/Godeps/_workspace/src/github.com/miekg/dns/zscan.go deleted file mode 100644 index 446228291..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/zscan.go +++ /dev/null @@ -1,964 +0,0 @@ -package dns - -import ( - "io" - "log" - "os" - "strconv" - "strings" -) - -type debugging bool - -const debug debugging = false - -func (d debugging) Printf(format string, args ...interface{}) { - if d { - log.Printf(format, args...) - } -} - -const maxTok = 2048 // Largest token we can return. -const maxUint16 = 1<<16 - 1 - -// Tokinize a RFC 1035 zone file. The tokenizer will normalize it: -// * Add ownernames if they are left blank; -// * Suppress sequences of spaces; -// * Make each RR fit on one line (_NEWLINE is send as last) -// * Handle comments: ; -// * Handle braces - anywhere. -const ( - // Zonefile - zEOF = iota - zString - zBlank - zQuote - zNewline - zRrtpe - zOwner - zClass - zDirOrigin // $ORIGIN - zDirTtl // $TTL - zDirInclude // $INCLUDE - zDirGenerate // $GENERATE - - // Privatekey file - zValue - zKey - - zExpectOwnerDir // Ownername - zExpectOwnerBl // Whitespace after the ownername - zExpectAny // Expect rrtype, ttl or class - zExpectAnyNoClass // Expect rrtype or ttl - zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS - zExpectAnyNoTtl // Expect rrtype or class - zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL - zExpectRrtype // Expect rrtype - zExpectRrtypeBl // Whitespace BEFORE rrtype - zExpectRdata // The first element of the rdata - zExpectDirTtlBl // Space after directive $TTL - zExpectDirTtl // Directive $TTL - zExpectDirOriginBl // Space after directive $ORIGIN - zExpectDirOrigin // Directive $ORIGIN - zExpectDirIncludeBl // Space after directive $INCLUDE - zExpectDirInclude // Directive $INCLUDE - zExpectDirGenerate // Directive $GENERATE - zExpectDirGenerateBl // Space after directive $GENERATE -) - -// ParseError is a parsing error. It contains the parse error and the location in the io.Reader -// where the error occured. -type ParseError struct { - file string - err string - lex lex -} - -func (e *ParseError) Error() (s string) { - if e.file != "" { - s = e.file + ": " - } - s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " + - strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column) - return -} - -type lex struct { - token string // text of the token - tokenUpper string // uppercase text of the token - length int // lenght of the token - err bool // when true, token text has lexer error - value uint8 // value: zString, _BLANK, etc. - line int // line in the file - column int // column in the file - torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar - comment string // any comment text seen -} - -// Token holds the token that are returned when a zone file is parsed. -type Token struct { - // The scanned resource record when error is not nil. - RR - // When an error occured, this has the error specifics. - Error *ParseError - // A potential comment positioned after the RR and on the same line. - Comment string -} - -// NewRR reads the RR contained in the string s. Only the first RR is -// returned. If s contains no RR, return nil with no error. The class -// defaults to IN and TTL defaults to 3600. The full zone file syntax -// like $TTL, $ORIGIN, etc. is supported. All fields of the returned -// RR are set, except RR.Header().Rdlength which is set to 0. -func NewRR(s string) (RR, error) { - if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline - return ReadRR(strings.NewReader(s+"\n"), "") - } - return ReadRR(strings.NewReader(s), "") -} - -// ReadRR reads the RR contained in q. -// See NewRR for more documentation. -func ReadRR(q io.Reader, filename string) (RR, error) { - r := <-parseZoneHelper(q, ".", filename, 1) - if r == nil { - return nil, nil - } - - if r.Error != nil { - return nil, r.Error - } - return r.RR, nil -} - -// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the -// returned channel, which consist out the parsed RR, a potential comment or an error. -// If there is an error the RR is nil. The string file is only used -// in error reporting. The string origin is used as the initial origin, as -// if the file would start with: $ORIGIN origin . -// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported. -// The channel t is closed by ParseZone when the end of r is reached. -// -// Basic usage pattern when reading from a string (z) containing the -// zone data: -// -// for x := range dns.ParseZone(strings.NewReader(z), "", "") { -// if x.Error != nil { -// // Do something with x.RR -// } -// } -// -// Comments specified after an RR (and on the same line!) are returned too: -// -// foo. IN A 10.0.0.1 ; this is a comment -// -// The text "; this is comment" is returned in Token.Comment . Comments inside the -// RR are discarded. Comments on a line by themselves are discarded too. -func ParseZone(r io.Reader, origin, file string) chan *Token { - return parseZoneHelper(r, origin, file, 10000) -} - -func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token { - t := make(chan *Token, chansize) - go parseZone(r, origin, file, t, 0) - return t -} - -func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { - defer func() { - if include == 0 { - close(t) - } - }() - s := scanInit(r) - c := make(chan lex) - // Start the lexer - go zlexer(s, c) - // 6 possible beginnings of a line, _ is a space - // 0. zRRTYPE -> all omitted until the rrtype - // 1. zOwner _ zRrtype -> class/ttl omitted - // 2. zOwner _ zString _ zRrtype -> class omitted - // 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class - // 4. zOwner _ zClass _ zRrtype -> ttl omitted - // 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed) - // After detecting these, we know the zRrtype so we can jump to functions - // handling the rdata for each of these types. - - if origin == "" { - origin = "." - } - origin = Fqdn(origin) - if _, ok := IsDomainName(origin); !ok { - t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}} - return - } - - st := zExpectOwnerDir // initial state - var h RR_Header - var defttl uint32 = defaultTtl - var prevName string - for l := range c { - // Lexer spotted an error already - if l.err == true { - t <- &Token{Error: &ParseError{f, l.token, l}} - return - - } - switch st { - case zExpectOwnerDir: - // We can also expect a directive, like $TTL or $ORIGIN - h.Ttl = defttl - h.Class = ClassINET - switch l.value { - case zNewline: - st = zExpectOwnerDir - case zOwner: - h.Name = l.token - if l.token[0] == '@' { - h.Name = origin - prevName = h.Name - st = zExpectOwnerBl - break - } - if h.Name[l.length-1] != '.' { - h.Name = appendOrigin(h.Name, origin) - } - _, ok := IsDomainName(l.token) - if !ok { - t <- &Token{Error: &ParseError{f, "bad owner name", l}} - return - } - prevName = h.Name - st = zExpectOwnerBl - case zDirTtl: - st = zExpectDirTtlBl - case zDirOrigin: - st = zExpectDirOriginBl - case zDirInclude: - st = zExpectDirIncludeBl - case zDirGenerate: - st = zExpectDirGenerateBl - case zRrtpe: - h.Name = prevName - h.Rrtype = l.torc - st = zExpectRdata - case zClass: - h.Name = prevName - h.Class = l.torc - st = zExpectAnyNoClassBl - case zBlank: - // Discard, can happen when there is nothing on the - // line except the RR type - case zString: - ttl, ok := stringToTtl(l.token) - if !ok { - t <- &Token{Error: &ParseError{f, "not a TTL", l}} - return - } - h.Ttl = ttl - // Don't about the defttl, we should take the $TTL value - // defttl = ttl - st = zExpectAnyNoTtlBl - - default: - t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}} - return - } - case zExpectDirIncludeBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}} - return - } - st = zExpectDirInclude - case zExpectDirInclude: - if l.value != zString { - t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}} - return - } - neworigin := origin // There may be optionally a new origin set after the filename, if not use current one - l := <-c - switch l.value { - case zBlank: - l := <-c - if l.value == zString { - if _, ok := IsDomainName(l.token); !ok { - t <- &Token{Error: &ParseError{f, "bad origin name", l}} - return - } - // a new origin is specified. - if l.token[l.length-1] != '.' { - if origin != "." { // Prevent .. endings - neworigin = l.token + "." + origin - } else { - neworigin = l.token + origin - } - } else { - neworigin = l.token - } - } - case zNewline, zEOF: - // Ok - default: - t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}} - return - } - // Start with the new file - r1, e1 := os.Open(l.token) - if e1 != nil { - t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}} - return - } - if include+1 > 7 { - t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}} - return - } - parseZone(r1, l.token, neworigin, t, include+1) - st = zExpectOwnerDir - case zExpectDirTtlBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}} - return - } - st = zExpectDirTtl - case zExpectDirTtl: - if l.value != zString { - t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} - return - } - if e, _ := slurpRemainder(c, f); e != nil { - t <- &Token{Error: e} - return - } - ttl, ok := stringToTtl(l.token) - if !ok { - t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} - return - } - defttl = ttl - st = zExpectOwnerDir - case zExpectDirOriginBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}} - return - } - st = zExpectDirOrigin - case zExpectDirOrigin: - if l.value != zString { - t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}} - return - } - if e, _ := slurpRemainder(c, f); e != nil { - t <- &Token{Error: e} - } - if _, ok := IsDomainName(l.token); !ok { - t <- &Token{Error: &ParseError{f, "bad origin name", l}} - return - } - if l.token[l.length-1] != '.' { - if origin != "." { // Prevent .. endings - origin = l.token + "." + origin - } else { - origin = l.token + origin - } - } else { - origin = l.token - } - st = zExpectOwnerDir - case zExpectDirGenerateBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}} - return - } - st = zExpectDirGenerate - case zExpectDirGenerate: - if l.value != zString { - t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}} - return - } - if e := generate(l, c, t, origin); e != "" { - t <- &Token{Error: &ParseError{f, e, l}} - return - } - st = zExpectOwnerDir - case zExpectOwnerBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank after owner", l}} - return - } - st = zExpectAny - case zExpectAny: - switch l.value { - case zRrtpe: - h.Rrtype = l.torc - st = zExpectRdata - case zClass: - h.Class = l.torc - st = zExpectAnyNoClassBl - case zString: - ttl, ok := stringToTtl(l.token) - if !ok { - t <- &Token{Error: &ParseError{f, "not a TTL", l}} - return - } - h.Ttl = ttl - // defttl = ttl // don't set the defttl here - st = zExpectAnyNoTtlBl - default: - t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}} - return - } - case zExpectAnyNoClassBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank before class", l}} - return - } - st = zExpectAnyNoClass - case zExpectAnyNoTtlBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank before TTL", l}} - return - } - st = zExpectAnyNoTtl - case zExpectAnyNoTtl: - switch l.value { - case zClass: - h.Class = l.torc - st = zExpectRrtypeBl - case zRrtpe: - h.Rrtype = l.torc - st = zExpectRdata - default: - t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}} - return - } - case zExpectAnyNoClass: - switch l.value { - case zString: - ttl, ok := stringToTtl(l.token) - if !ok { - t <- &Token{Error: &ParseError{f, "not a TTL", l}} - return - } - h.Ttl = ttl - // defttl = ttl // don't set the def ttl anymore - st = zExpectRrtypeBl - case zRrtpe: - h.Rrtype = l.torc - st = zExpectRdata - default: - t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}} - return - } - case zExpectRrtypeBl: - if l.value != zBlank { - t <- &Token{Error: &ParseError{f, "no blank before RR type", l}} - return - } - st = zExpectRrtype - case zExpectRrtype: - if l.value != zRrtpe { - t <- &Token{Error: &ParseError{f, "unknown RR type", l}} - return - } - h.Rrtype = l.torc - st = zExpectRdata - case zExpectRdata: - r, e, c1 := setRR(h, c, origin, f) - if e != nil { - // If e.lex is nil than we have encounter a unknown RR type - // in that case we substitute our current lex token - if e.lex.token == "" && e.lex.value == 0 { - e.lex = l // Uh, dirty - } - t <- &Token{Error: e} - return - } - t <- &Token{RR: r, Comment: c1} - st = zExpectOwnerDir - } - } - // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this - // is not an error, because an empty zone file is still a zone file. -} - -// zlexer scans the sourcefile and returns tokens on the channel c. -func zlexer(s *scan, c chan lex) { - var l lex - str := make([]byte, maxTok) // Should be enough for any token - stri := 0 // Offset in str (0 means empty) - com := make([]byte, maxTok) // Hold comment text - comi := 0 - quote := false - escape := false - space := false - commt := false - rrtype := false - owner := true - brace := 0 - x, err := s.tokenText() - defer close(c) - for err == nil { - l.column = s.position.Column - l.line = s.position.Line - if stri > maxTok { - l.token = "token length insufficient for parsing" - l.err = true - debug.Printf("[%+v]", l.token) - c <- l - return - } - if comi > maxTok { - l.token = "comment length insufficient for parsing" - l.err = true - debug.Printf("[%+v]", l.token) - c <- l - return - } - - switch x { - case ' ', '\t': - if escape { - escape = false - str[stri] = x - stri++ - break - } - if quote { - // Inside quotes this is legal - str[stri] = x - stri++ - break - } - if commt { - com[comi] = x - comi++ - break - } - if stri == 0 { - // Space directly in the beginning, handled in the grammar - } else if owner { - // If we have a string and its the first, make it an owner - l.value = zOwner - l.token = string(str[:stri]) - l.tokenUpper = strings.ToUpper(l.token) - l.length = stri - // escape $... start with a \ not a $, so this will work - switch l.tokenUpper { - case "$TTL": - l.value = zDirTtl - case "$ORIGIN": - l.value = zDirOrigin - case "$INCLUDE": - l.value = zDirInclude - case "$GENERATE": - l.value = zDirGenerate - } - debug.Printf("[7 %+v]", l.token) - c <- l - } else { - l.value = zString - l.token = string(str[:stri]) - l.tokenUpper = strings.ToUpper(l.token) - l.length = stri - if !rrtype { - if t, ok := StringToType[l.tokenUpper]; ok { - l.value = zRrtpe - l.torc = t - rrtype = true - } else { - if strings.HasPrefix(l.tokenUpper, "TYPE") { - t, ok := typeToInt(l.token) - if !ok { - l.token = "unknown RR type" - l.err = true - c <- l - return - } - l.value = zRrtpe - l.torc = t - } - } - if t, ok := StringToClass[l.tokenUpper]; ok { - l.value = zClass - l.torc = t - } else { - if strings.HasPrefix(l.tokenUpper, "CLASS") { - t, ok := classToInt(l.token) - if !ok { - l.token = "unknown class" - l.err = true - c <- l - return - } - l.value = zClass - l.torc = t - } - } - } - debug.Printf("[6 %+v]", l.token) - c <- l - } - stri = 0 - // I reverse space stuff here - if !space && !commt { - l.value = zBlank - l.token = " " - l.length = 1 - debug.Printf("[5 %+v]", l.token) - c <- l - } - owner = false - space = true - case ';': - if escape { - escape = false - str[stri] = x - stri++ - break - } - if quote { - // Inside quotes this is legal - str[stri] = x - stri++ - break - } - if stri > 0 { - l.value = zString - l.token = string(str[:stri]) - l.length = stri - debug.Printf("[4 %+v]", l.token) - c <- l - stri = 0 - } - commt = true - com[comi] = ';' - comi++ - case '\r': - escape = false - if quote { - str[stri] = x - stri++ - break - } - // discard if outside of quotes - case '\n': - escape = false - // Escaped newline - if quote { - str[stri] = x - stri++ - break - } - // inside quotes this is legal - if commt { - // Reset a comment - commt = false - rrtype = false - stri = 0 - // If not in a brace this ends the comment AND the RR - if brace == 0 { - owner = true - owner = true - l.value = zNewline - l.token = "\n" - l.length = 1 - l.comment = string(com[:comi]) - debug.Printf("[3 %+v %+v]", l.token, l.comment) - c <- l - l.comment = "" - comi = 0 - break - } - com[comi] = ' ' // convert newline to space - comi++ - break - } - - if brace == 0 { - // If there is previous text, we should output it here - if stri != 0 { - l.value = zString - l.token = string(str[:stri]) - l.tokenUpper = strings.ToUpper(l.token) - - l.length = stri - if !rrtype { - if t, ok := StringToType[l.tokenUpper]; ok { - l.value = zRrtpe - l.torc = t - rrtype = true - } - } - debug.Printf("[2 %+v]", l.token) - c <- l - } - l.value = zNewline - l.token = "\n" - l.length = 1 - debug.Printf("[1 %+v]", l.token) - c <- l - stri = 0 - commt = false - rrtype = false - owner = true - comi = 0 - } - case '\\': - // comments do not get escaped chars, everything is copied - if commt { - com[comi] = x - comi++ - break - } - // something already escaped must be in string - if escape { - str[stri] = x - stri++ - escape = false - break - } - // something escaped outside of string gets added to string - str[stri] = x - stri++ - escape = true - case '"': - if commt { - com[comi] = x - comi++ - break - } - if escape { - str[stri] = x - stri++ - escape = false - break - } - space = false - // send previous gathered text and the quote - if stri != 0 { - l.value = zString - l.token = string(str[:stri]) - l.length = stri - - debug.Printf("[%+v]", l.token) - c <- l - stri = 0 - } - - // send quote itself as separate token - l.value = zQuote - l.token = "\"" - l.length = 1 - c <- l - quote = !quote - case '(', ')': - if commt { - com[comi] = x - comi++ - break - } - if escape { - str[stri] = x - stri++ - escape = false - break - } - if quote { - str[stri] = x - stri++ - break - } - switch x { - case ')': - brace-- - if brace < 0 { - l.token = "extra closing brace" - l.err = true - debug.Printf("[%+v]", l.token) - c <- l - return - } - case '(': - brace++ - } - default: - escape = false - if commt { - com[comi] = x - comi++ - break - } - str[stri] = x - stri++ - space = false - } - x, err = s.tokenText() - } - if stri > 0 { - // Send remainder - l.token = string(str[:stri]) - l.length = stri - l.value = zString - debug.Printf("[%+v]", l.token) - c <- l - } -} - -// Extract the class number from CLASSxx -func classToInt(token string) (uint16, bool) { - class, ok := strconv.Atoi(token[5:]) - if ok != nil || class > maxUint16 { - return 0, false - } - return uint16(class), true -} - -// Extract the rr number from TYPExxx -func typeToInt(token string) (uint16, bool) { - typ, ok := strconv.Atoi(token[4:]) - if ok != nil || typ > maxUint16 { - return 0, false - } - return uint16(typ), true -} - -// Parse things like 2w, 2m, etc, Return the time in seconds. -func stringToTtl(token string) (uint32, bool) { - s := uint32(0) - i := uint32(0) - for _, c := range token { - switch c { - case 's', 'S': - s += i - i = 0 - case 'm', 'M': - s += i * 60 - i = 0 - case 'h', 'H': - s += i * 60 * 60 - i = 0 - case 'd', 'D': - s += i * 60 * 60 * 24 - i = 0 - case 'w', 'W': - s += i * 60 * 60 * 24 * 7 - i = 0 - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i *= 10 - i += uint32(c) - '0' - default: - return 0, false - } - } - return s + i, true -} - -// Parse LOC records' [.][mM] into a -// mantissa exponent format. Token should contain the entire -// string (i.e. no spaces allowed) -func stringToCm(token string) (e, m uint8, ok bool) { - if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' { - token = token[0 : len(token)-1] - } - s := strings.SplitN(token, ".", 2) - var meters, cmeters, val int - var err error - switch len(s) { - case 2: - if cmeters, err = strconv.Atoi(s[1]); err != nil { - return - } - fallthrough - case 1: - if meters, err = strconv.Atoi(s[0]); err != nil { - return - } - case 0: - // huh? - return 0, 0, false - } - ok = true - if meters > 0 { - e = 2 - val = meters - } else { - e = 0 - val = cmeters - } - for val > 10 { - e++ - val /= 10 - } - if e > 9 { - ok = false - } - m = uint8(val) - return -} - -func appendOrigin(name, origin string) string { - if origin == "." { - return name + origin - } - return name + "." + origin -} - -// LOC record helper function -func locCheckNorth(token string, latitude uint32) (uint32, bool) { - switch token { - case "n", "N": - return LOC_EQUATOR + latitude, true - case "s", "S": - return LOC_EQUATOR - latitude, true - } - return latitude, false -} - -// LOC record helper function -func locCheckEast(token string, longitude uint32) (uint32, bool) { - switch token { - case "e", "E": - return LOC_EQUATOR + longitude, true - case "w", "W": - return LOC_EQUATOR - longitude, true - } - return longitude, false -} - -// "Eat" the rest of the "line". Return potential comments -func slurpRemainder(c chan lex, f string) (*ParseError, string) { - l := <-c - com := "" - switch l.value { - case zBlank: - l = <-c - com = l.comment - if l.value != zNewline && l.value != zEOF { - return &ParseError{f, "garbage after rdata", l}, "" - } - case zNewline: - com = l.comment - case zEOF: - default: - return &ParseError{f, "garbage after rdata", l}, "" - } - return nil, com -} - -// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64" -// Used for NID and L64 record. -func stringToNodeID(l lex) (uint64, *ParseError) { - if len(l.token) < 19 { - return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l} - } - // There must be three colons at fixes postitions, if not its a parse error - if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' { - return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l} - } - s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19] - u, e := strconv.ParseUint(s, 16, 64) - if e != nil { - return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l} - } - return u, nil -} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go b/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go deleted file mode 100644 index 1ffd13c41..000000000 --- a/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go +++ /dev/null @@ -1,2202 +0,0 @@ -package dns - -import ( - "encoding/base64" - "net" - "strconv" - "strings" -) - -type parserFunc struct { - // Func defines the function that parses the tokens and returns the RR - // or an error. The last string contains any comments in the line as - // they returned by the lexer as well. - Func func(h RR_Header, c chan lex, origin string, file string) (RR, *ParseError, string) - // Signals if the RR ending is of variable length, like TXT or records - // that have Hexadecimal or Base64 as their last element in the Rdata. Records - // that have a fixed ending or for instance A, AAAA, SOA and etc. - Variable bool -} - -// Parse the rdata of each rrtype. -// All data from the channel c is either zString or zBlank. -// After the rdata there may come a zBlank and then a zNewline -// or immediately a zNewline. If this is not the case we flag -// an *ParseError: garbage after rdata. -func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - parserfunc, ok := typeToparserFunc[h.Rrtype] - if ok { - r, e, cm := parserfunc.Func(h, c, o, f) - if parserfunc.Variable { - return r, e, cm - } - if e != nil { - return nil, e, "" - } - e, cm = slurpRemainder(c, f) - if e != nil { - return nil, e, "" - } - return r, nil, cm - } - // RFC3957 RR (Unknown RR handling) - return setRFC3597(h, c, o, f) -} - -// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces) -// or an error -func endingToString(c chan lex, errstr, f string) (string, *ParseError, string) { - s := "" - l := <-c // zString - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zString: - s += l.token - case zBlank: // Ok - default: - return "", &ParseError{f, errstr, l}, "" - } - l = <-c - } - return s, nil, l.comment -} - -// A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces) -// or an error -func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) { - // Get the remaining data until we see a zNewline - quote := false - l := <-c - var s []string - switch l.value == zQuote { - case true: // A number of quoted string - s = make([]string, 0) - empty := true - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zString: - empty = false - if len(l.token) > 255 { - // split up tokens that are larger than 255 into 255-chunks - sx := []string{} - p, i := 0, 255 - for { - if i <= len(l.token) { - sx = append(sx, l.token[p:i]) - } else { - sx = append(sx, l.token[p:]) - break - - } - p, i = p+255, i+255 - } - s = append(s, sx...) - break; - } - - s = append(s, l.token) - case zBlank: - if quote { - // zBlank can only be seen in between txt parts. - return nil, &ParseError{f, errstr, l}, "" - } - case zQuote: - if empty && quote { - s = append(s, "") - } - quote = !quote - empty = true - default: - return nil, &ParseError{f, errstr, l}, "" - } - l = <-c - } - if quote { - return nil, &ParseError{f, errstr, l}, "" - } - case false: // Unquoted text record - s = make([]string, 1) - for l.value != zNewline && l.value != zEOF { - s[0] += l.token - l = <-c - } - } - return s, nil, l.comment -} - -func setA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(A) - rr.Hdr = h - - l := <-c - if l.length == 0 { // Dynamic updates. - return rr, nil, "" - } - rr.A = net.ParseIP(l.token) - if rr.A == nil { - return nil, &ParseError{f, "bad A A", l}, "" - } - return rr, nil, "" -} - -func setAAAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(AAAA) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - rr.AAAA = net.ParseIP(l.token) - if rr.AAAA == nil { - return nil, &ParseError{f, "bad AAAA AAAA", l}, "" - } - return rr, nil, "" -} - -func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NS) - rr.Hdr = h - - l := <-c - rr.Ns = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Ns = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad NS Ns", l}, "" - } - if rr.Ns[l.length-1] != '.' { - rr.Ns = appendOrigin(rr.Ns, o) - } - return rr, nil, "" -} - -func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(PTR) - rr.Hdr = h - - l := <-c - rr.Ptr = l.token - if l.length == 0 { // dynamic update rr. - return rr, nil, "" - } - if l.token == "@" { - rr.Ptr = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad PTR Ptr", l}, "" - } - if rr.Ptr[l.length-1] != '.' { - rr.Ptr = appendOrigin(rr.Ptr, o) - } - return rr, nil, "" -} - -func setNSAPPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSAPPTR) - rr.Hdr = h - - l := <-c - rr.Ptr = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Ptr = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, "" - } - if rr.Ptr[l.length-1] != '.' { - rr.Ptr = appendOrigin(rr.Ptr, o) - } - return rr, nil, "" -} - -func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(RP) - rr.Hdr = h - - l := <-c - rr.Mbox = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mbox = o - } else { - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad RP Mbox", l}, "" - } - if rr.Mbox[l.length-1] != '.' { - rr.Mbox = appendOrigin(rr.Mbox, o) - } - } - <-c // zBlank - l = <-c - rr.Txt = l.token - if l.token == "@" { - rr.Txt = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad RP Txt", l}, "" - } - if rr.Txt[l.length-1] != '.' { - rr.Txt = appendOrigin(rr.Txt, o) - } - return rr, nil, "" -} - -func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MR) - rr.Hdr = h - - l := <-c - rr.Mr = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mr = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MR Mr", l}, "" - } - if rr.Mr[l.length-1] != '.' { - rr.Mr = appendOrigin(rr.Mr, o) - } - return rr, nil, "" -} - -func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MB) - rr.Hdr = h - - l := <-c - rr.Mb = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mb = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MB Mb", l}, "" - } - if rr.Mb[l.length-1] != '.' { - rr.Mb = appendOrigin(rr.Mb, o) - } - return rr, nil, "" -} - -func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MG) - rr.Hdr = h - - l := <-c - rr.Mg = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mg = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MG Mg", l}, "" - } - if rr.Mg[l.length-1] != '.' { - rr.Mg = appendOrigin(rr.Mg, o) - } - return rr, nil, "" -} - -func setHINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(HINFO) - rr.Hdr = h - - l := <-c - rr.Cpu = l.token - <-c // zBlank - l = <-c // zString - rr.Os = l.token - - return rr, nil, "" -} - -func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MINFO) - rr.Hdr = h - - l := <-c - rr.Rmail = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Rmail = o - } else { - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MINFO Rmail", l}, "" - } - if rr.Rmail[l.length-1] != '.' { - rr.Rmail = appendOrigin(rr.Rmail, o) - } - } - <-c // zBlank - l = <-c - rr.Email = l.token - if l.token == "@" { - rr.Email = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MINFO Email", l}, "" - } - if rr.Email[l.length-1] != '.' { - rr.Email = appendOrigin(rr.Email, o) - } - return rr, nil, "" -} - -func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MF) - rr.Hdr = h - - l := <-c - rr.Mf = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Mf = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MF Mf", l}, "" - } - if rr.Mf[l.length-1] != '.' { - rr.Mf = appendOrigin(rr.Mf, o) - } - return rr, nil, "" -} - -func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MD) - rr.Hdr = h - - l := <-c - rr.Md = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Md = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad MD Md", l}, "" - } - if rr.Md[l.length-1] != '.' { - rr.Md = appendOrigin(rr.Md, o) - } - return rr, nil, "" -} - -func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(MX) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad MX Pref", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Mx = l.token - if l.token == "@" { - rr.Mx = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad MX Mx", l}, "" - } - if rr.Mx[l.length-1] != '.' { - rr.Mx = appendOrigin(rr.Mx, o) - } - return rr, nil, "" -} - -func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(RT) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad RT Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Host = l.token - if l.token == "@" { - rr.Host = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad RT Host", l}, "" - } - if rr.Host[l.length-1] != '.' { - rr.Host = appendOrigin(rr.Host, o) - } - return rr, nil, "" -} - -func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(AFSDB) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad AFSDB Subtype", l}, "" - } - rr.Subtype = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Hostname = l.token - if l.token == "@" { - rr.Hostname = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad AFSDB Hostname", l}, "" - } - if rr.Hostname[l.length-1] != '.' { - rr.Hostname = appendOrigin(rr.Hostname, o) - } - return rr, nil, "" -} - -func setX25(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(X25) - rr.Hdr = h - - l := <-c - rr.PSDNAddress = l.token - return rr, nil, "" -} - -func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(KX) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad KX Pref", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Exchanger = l.token - if l.token == "@" { - rr.Exchanger = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad KX Exchanger", l}, "" - } - if rr.Exchanger[l.length-1] != '.' { - rr.Exchanger = appendOrigin(rr.Exchanger, o) - } - return rr, nil, "" -} - -func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(CNAME) - rr.Hdr = h - - l := <-c - rr.Target = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Target = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad CNAME Target", l}, "" - } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) - } - return rr, nil, "" -} - -func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(DNAME) - rr.Hdr = h - - l := <-c - rr.Target = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Target = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad CNAME Target", l}, "" - } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) - } - return rr, nil, "" -} - -func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(SOA) - rr.Hdr = h - - l := <-c - rr.Ns = l.token - if l.length == 0 { - return rr, nil, "" - } - <-c // zBlank - if l.token == "@" { - rr.Ns = o - } else { - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad SOA Ns", l}, "" - } - if rr.Ns[l.length-1] != '.' { - rr.Ns = appendOrigin(rr.Ns, o) - } - } - - l = <-c - rr.Mbox = l.token - if l.token == "@" { - rr.Mbox = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad SOA Mbox", l}, "" - } - if rr.Mbox[l.length-1] != '.' { - rr.Mbox = appendOrigin(rr.Mbox, o) - } - } - <-c // zBlank - - var ( - v uint32 - ok bool - ) - for i := 0; i < 5; i++ { - l = <-c - if j, e := strconv.Atoi(l.token); e != nil { - if i == 0 { - // Serial should be a number - return nil, &ParseError{f, "bad SOA zone parameter", l}, "" - } - if v, ok = stringToTtl(l.token); !ok { - return nil, &ParseError{f, "bad SOA zone parameter", l}, "" - - } - } else { - v = uint32(j) - } - switch i { - case 0: - rr.Serial = v - <-c // zBlank - case 1: - rr.Refresh = v - <-c // zBlank - case 2: - rr.Retry = v - <-c // zBlank - case 3: - rr.Expire = v - <-c // zBlank - case 4: - rr.Minttl = v - } - } - return rr, nil, "" -} - -func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(SRV) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad SRV Priority", l}, "" - } - rr.Priority = uint16(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad SRV Weight", l}, "" - } - rr.Weight = uint16(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad SRV Port", l}, "" - } - rr.Port = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Target = l.token - if l.token == "@" { - rr.Target = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad SRV Target", l}, "" - } - if rr.Target[l.length-1] != '.' { - rr.Target = appendOrigin(rr.Target, o) - } - return rr, nil, "" -} - -func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NAPTR) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NAPTR Order", l}, "" - } - rr.Order = uint16(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NAPTR Preference", l}, "" - } - rr.Preference = uint16(i) - // Flags - <-c // zBlank - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Flags", l}, "" - } - l = <-c // Either String or Quote - if l.value == zString { - rr.Flags = l.token - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Flags", l}, "" - } - } else if l.value == zQuote { - rr.Flags = "" - } else { - return nil, &ParseError{f, "bad NAPTR Flags", l}, "" - } - - // Service - <-c // zBlank - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Service", l}, "" - } - l = <-c // Either String or Quote - if l.value == zString { - rr.Service = l.token - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Service", l}, "" - } - } else if l.value == zQuote { - rr.Service = "" - } else { - return nil, &ParseError{f, "bad NAPTR Service", l}, "" - } - - // Regexp - <-c // zBlank - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" - } - l = <-c // Either String or Quote - if l.value == zString { - rr.Regexp = l.token - l = <-c // _QUOTE - if l.value != zQuote { - return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" - } - } else if l.value == zQuote { - rr.Regexp = "" - } else { - return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" - } - // After quote no space?? - <-c // zBlank - l = <-c // zString - rr.Replacement = l.token - if l.token == "@" { - rr.Replacement = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad NAPTR Replacement", l}, "" - } - if rr.Replacement[l.length-1] != '.' { - rr.Replacement = appendOrigin(rr.Replacement, o) - } - return rr, nil, "" -} - -func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(TALINK) - rr.Hdr = h - - l := <-c - rr.PreviousName = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.PreviousName = o - } else { - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad TALINK PreviousName", l}, "" - } - if rr.PreviousName[l.length-1] != '.' { - rr.PreviousName = appendOrigin(rr.PreviousName, o) - } - } - <-c // zBlank - l = <-c - rr.NextName = l.token - if l.token == "@" { - rr.NextName = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad TALINK NextName", l}, "" - } - if rr.NextName[l.length-1] != '.' { - rr.NextName = appendOrigin(rr.NextName, o) - } - return rr, nil, "" -} - -func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(LOC) - rr.Hdr = h - // Non zero defaults for LOC record, see RFC 1876, Section 3. - rr.HorizPre = 165 // 10000 - rr.VertPre = 162 // 10 - rr.Size = 18 // 1 - ok := false - // North - l := <-c - if l.length == 0 { - return rr, nil, "" - } - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad LOC Latitude", l}, "" - } else { - rr.Latitude = 1000 * 60 * 60 * uint32(i) - } - <-c // zBlank - // Either number, 'N' or 'S' - l = <-c - if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { - goto East - } - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad LOC Latitude minutes", l}, "" - } else { - rr.Latitude += 1000 * 60 * uint32(i) - } - <-c // zBlank - l = <-c - if i, e := strconv.ParseFloat(l.token, 32); e != nil { - return nil, &ParseError{f, "bad LOC Latitude seconds", l}, "" - } else { - rr.Latitude += uint32(1000 * i) - } - <-c // zBlank - // Either number, 'N' or 'S' - l = <-c - if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { - goto East - } - // If still alive, flag an error - return nil, &ParseError{f, "bad LOC Latitude North/South", l}, "" - -East: - // East - <-c // zBlank - l = <-c - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad LOC Longitude", l}, "" - } else { - rr.Longitude = 1000 * 60 * 60 * uint32(i) - } - <-c // zBlank - // Either number, 'E' or 'W' - l = <-c - if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { - goto Altitude - } - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad LOC Longitude minutes", l}, "" - } else { - rr.Longitude += 1000 * 60 * uint32(i) - } - <-c // zBlank - l = <-c - if i, e := strconv.ParseFloat(l.token, 32); e != nil { - return nil, &ParseError{f, "bad LOC Longitude seconds", l}, "" - } else { - rr.Longitude += uint32(1000 * i) - } - <-c // zBlank - // Either number, 'E' or 'W' - l = <-c - if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { - goto Altitude - } - // If still alive, flag an error - return nil, &ParseError{f, "bad LOC Longitude East/West", l}, "" - -Altitude: - <-c // zBlank - l = <-c - if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' { - l.token = l.token[0 : len(l.token)-1] - } - if i, e := strconv.ParseFloat(l.token, 32); e != nil { - return nil, &ParseError{f, "bad LOC Altitude", l}, "" - } else { - rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5) - } - - // And now optionally the other values - l = <-c - count := 0 - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zString: - switch count { - case 0: // Size - e, m, ok := stringToCm(l.token) - if !ok { - return nil, &ParseError{f, "bad LOC Size", l}, "" - } - rr.Size = (e & 0x0f) | (m << 4 & 0xf0) - case 1: // HorizPre - e, m, ok := stringToCm(l.token) - if !ok { - return nil, &ParseError{f, "bad LOC HorizPre", l}, "" - } - rr.HorizPre = (e & 0x0f) | (m << 4 & 0xf0) - case 2: // VertPre - e, m, ok := stringToCm(l.token) - if !ok { - return nil, &ParseError{f, "bad LOC VertPre", l}, "" - } - rr.VertPre = (e & 0x0f) | (m << 4 & 0xf0) - } - count++ - case zBlank: - // Ok - default: - return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, "" - } - l = <-c - } - return rr, nil, "" -} - -func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(HIP) - rr.Hdr = h - - // HitLength is not represented - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, "" - } - rr.PublicKeyAlgorithm = uint8(i) - <-c // zBlank - l = <-c // zString - rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6. - rr.HitLength = uint8(len(rr.Hit)) / 2 - - <-c // zBlank - l = <-c // zString - rr.PublicKey = l.token // This cannot contain spaces - rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey))) - - // RendezvousServers (if any) - l = <-c - var xs []string - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zString: - if l.token == "@" { - xs = append(xs, o) - continue - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" - } - if l.token[l.length-1] != '.' { - l.token = appendOrigin(l.token, o) - } - xs = append(xs, l.token) - case zBlank: - // Ok - default: - return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" - } - l = <-c - } - rr.RendezvousServers = xs - return rr, nil, l.comment -} - -func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(CERT) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - if v, ok := StringToCertType[l.token]; ok { - rr.Type = v - } else if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad CERT Type", l}, "" - } else { - rr.Type = uint16(i) - } - <-c // zBlank - l = <-c // zString - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad CERT KeyTag", l}, "" - } - rr.KeyTag = uint16(i) - <-c // zBlank - l = <-c // zString - if v, ok := StringToAlgorithm[l.token]; ok { - rr.Algorithm = v - } else if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad CERT Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) - } - s, e1, c1 := endingToString(c, "bad CERT Certificate", f) - if e1 != nil { - return nil, e1, c1 - } - rr.Certificate = s - return rr, nil, c1 -} - -func setOPENPGPKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(OPENPGPKEY) - rr.Hdr = h - - s, e, c1 := endingToString(c, "bad OPENPGPKEY PublicKey", f) - if e != nil { - return nil, e, c1 - } - rr.PublicKey = s - return rr, nil, c1 -} - -func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setRRSIG(h, c, o, f) - if r != nil { - return &SIG{*r.(*RRSIG)}, e, s - } - return nil, e, s -} - -func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(RRSIG) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - if t, ok := StringToType[l.tokenUpper]; !ok { - if strings.HasPrefix(l.tokenUpper, "TYPE") { - t, ok = typeToInt(l.tokenUpper) - if !ok { - return nil, &ParseError{f, "bad RRSIG Typecovered", l}, "" - } - rr.TypeCovered = t - } else { - return nil, &ParseError{f, "bad RRSIG Typecovered", l}, "" - } - } else { - rr.TypeCovered = t - } - <-c // zBlank - l = <-c - i, err := strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad RRSIG Algorithm", l}, "" - } - rr.Algorithm = uint8(i) - <-c // zBlank - l = <-c - i, err = strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad RRSIG Labels", l}, "" - } - rr.Labels = uint8(i) - <-c // zBlank - l = <-c - i, err = strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, "" - } - rr.OrigTtl = uint32(i) - <-c // zBlank - l = <-c - if i, err := StringToTime(l.token); err != nil { - // Try to see if all numeric and use it as epoch - if i, err := strconv.ParseInt(l.token, 10, 64); err == nil { - // TODO(miek): error out on > MAX_UINT32, same below - rr.Expiration = uint32(i) - } else { - return nil, &ParseError{f, "bad RRSIG Expiration", l}, "" - } - } else { - rr.Expiration = i - } - <-c // zBlank - l = <-c - if i, err := StringToTime(l.token); err != nil { - if i, err := strconv.ParseInt(l.token, 10, 64); err == nil { - rr.Inception = uint32(i) - } else { - return nil, &ParseError{f, "bad RRSIG Inception", l}, "" - } - } else { - rr.Inception = i - } - <-c // zBlank - l = <-c - i, err = strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad RRSIG KeyTag", l}, "" - } - rr.KeyTag = uint16(i) - <-c // zBlank - l = <-c - rr.SignerName = l.token - if l.token == "@" { - rr.SignerName = o - } else { - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" - } - if rr.SignerName[l.length-1] != '.' { - rr.SignerName = appendOrigin(rr.SignerName, o) - } - } - s, e, c1 := endingToString(c, "bad RRSIG Signature", f) - if e != nil { - return nil, e, c1 - } - rr.Signature = s - return rr, nil, c1 -} - -func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSEC) - rr.Hdr = h - - l := <-c - rr.NextDomain = l.token - if l.length == 0 { - return rr, nil, l.comment - } - if l.token == "@" { - rr.NextDomain = o - } else { - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" - } - if rr.NextDomain[l.length-1] != '.' { - rr.NextDomain = appendOrigin(rr.NextDomain, o) - } - } - - rr.TypeBitMap = make([]uint16, 0) - var ( - k uint16 - ok bool - ) - l = <-c - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zBlank: - // Ok - case zString: - if k, ok = StringToType[l.tokenUpper]; !ok { - if k, ok = typeToInt(l.tokenUpper); !ok { - return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, "" - } - } - rr.TypeBitMap = append(rr.TypeBitMap, k) - default: - return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, "" - } - l = <-c - } - return rr, nil, l.comment -} - -func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSEC3) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3 Hash", l}, "" - } - rr.Hash = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3 Flags", l}, "" - } - rr.Flags = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3 Iterations", l}, "" - } - rr.Iterations = uint16(i) - <-c - l = <-c - if len(l.token) == 0 { - return nil, &ParseError{f, "bad NSEC3 Salt", l}, "" - } - rr.SaltLength = uint8(len(l.token)) / 2 - rr.Salt = l.token - - <-c - l = <-c - rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits) - rr.NextDomain = l.token - - rr.TypeBitMap = make([]uint16, 0) - var ( - k uint16 - ok bool - ) - l = <-c - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zBlank: - // Ok - case zString: - if k, ok = StringToType[l.tokenUpper]; !ok { - if k, ok = typeToInt(l.tokenUpper); !ok { - return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, "" - } - } - rr.TypeBitMap = append(rr.TypeBitMap, k) - default: - return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, "" - } - l = <-c - } - return rr, nil, l.comment -} - -func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSEC3PARAM) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, "" - } - rr.Hash = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, "" - } - rr.Flags = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, "" - } - rr.Iterations = uint16(i) - <-c - l = <-c - rr.SaltLength = uint8(len(l.token)) - rr.Salt = l.token - return rr, nil, "" -} - -func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(EUI48) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - if l.length != 17 { - return nil, &ParseError{f, "bad EUI48 Address", l}, "" - } - addr := make([]byte, 12) - dash := 0 - for i := 0; i < 10; i += 2 { - addr[i] = l.token[i+dash] - addr[i+1] = l.token[i+1+dash] - dash++ - if l.token[i+1+dash] != '-' { - return nil, &ParseError{f, "bad EUI48 Address", l}, "" - } - } - addr[10] = l.token[15] - addr[11] = l.token[16] - - i, e := strconv.ParseUint(string(addr), 16, 48) - if e != nil { - return nil, &ParseError{f, "bad EUI48 Address", l}, "" - } - rr.Address = i - return rr, nil, "" -} - -func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(EUI64) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - if l.length != 23 { - return nil, &ParseError{f, "bad EUI64 Address", l}, "" - } - addr := make([]byte, 16) - dash := 0 - for i := 0; i < 14; i += 2 { - addr[i] = l.token[i+dash] - addr[i+1] = l.token[i+1+dash] - dash++ - if l.token[i+1+dash] != '-' { - return nil, &ParseError{f, "bad EUI64 Address", l}, "" - } - } - addr[14] = l.token[21] - addr[15] = l.token[22] - - i, e := strconv.ParseUint(string(addr), 16, 64) - if e != nil { - return nil, &ParseError{f, "bad EUI68 Address", l}, "" - } - rr.Address = uint64(i) - return rr, nil, "" -} - -func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(WKS) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - rr.Address = net.ParseIP(l.token) - if rr.Address == nil { - return nil, &ParseError{f, "bad WKS Address", l}, "" - } - - <-c // zBlank - l = <-c - proto := "tcp" - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad WKS Protocol", l}, "" - } - rr.Protocol = uint8(i) - switch rr.Protocol { - case 17: - proto = "udp" - case 6: - proto = "tcp" - default: - return nil, &ParseError{f, "bad WKS Protocol", l}, "" - } - - <-c - l = <-c - rr.BitMap = make([]uint16, 0) - var ( - k int - err error - ) - for l.value != zNewline && l.value != zEOF { - switch l.value { - case zBlank: - // Ok - case zString: - if k, err = net.LookupPort(proto, l.token); err != nil { - if i, e := strconv.Atoi(l.token); e != nil { // If a number use that - rr.BitMap = append(rr.BitMap, uint16(i)) - } else { - return nil, &ParseError{f, "bad WKS BitMap", l}, "" - } - } - rr.BitMap = append(rr.BitMap, uint16(k)) - default: - return nil, &ParseError{f, "bad WKS BitMap", l}, "" - } - l = <-c - } - return rr, nil, l.comment -} - -func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(SSHFP) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad SSHFP Algorithm", l}, "" - } - rr.Algorithm = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad SSHFP Type", l}, "" - } - rr.Type = uint8(i) - <-c // zBlank - l = <-c - rr.FingerPrint = l.token - return rr, nil, "" -} - -func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) { - rr := new(DNSKEY) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad " + typ + " Flags", l}, "" - } - rr.Flags = uint16(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad " + typ + " Protocol", l}, "" - } - rr.Protocol = uint8(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" - } - rr.Algorithm = uint8(i) - s, e1, c1 := endingToString(c, "bad "+typ+" PublicKey", f) - if e1 != nil { - return nil, e1, c1 - } - rr.PublicKey = s - return rr, nil, c1 -} - -func setKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDNSKEYs(h, c, o, f, "KEY") - if r != nil { - return &KEY{*r.(*DNSKEY)}, e, s - } - return nil, e, s -} - -func setDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDNSKEYs(h, c, o, f, "DNSKEY") - return r, e, s -} - -func setCDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDNSKEYs(h, c, o, f, "CDNSKEY") - if r != nil { - return &CDNSKEY{*r.(*DNSKEY)}, e, s - } - return nil, e, s -} - -func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(RKEY) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad RKEY Flags", l}, "" - } - rr.Flags = uint16(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad RKEY Protocol", l}, "" - } - rr.Protocol = uint8(i) - <-c // zBlank - l = <-c // zString - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad RKEY Algorithm", l}, "" - } - rr.Algorithm = uint8(i) - s, e1, c1 := endingToString(c, "bad RKEY PublicKey", f) - if e1 != nil { - return nil, e1, c1 - } - rr.PublicKey = s - return rr, nil, c1 -} - -func setEID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(EID) - rr.Hdr = h - s, e, c1 := endingToString(c, "bad EID Endpoint", f) - if e != nil { - return nil, e, c1 - } - rr.Endpoint = s - return rr, nil, c1 -} - -func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NIMLOC) - rr.Hdr = h - s, e, c1 := endingToString(c, "bad NIMLOC Locator", f) - if e != nil { - return nil, e, c1 - } - rr.Locator = s - return rr, nil, c1 -} - -func setNSAP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSAP) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSAP Length", l}, "" - } - rr.Length = uint8(i) - <-c // zBlank - s, e1, c1 := endingToString(c, "bad NSAP Nsap", f) - if e != nil { - return nil, e1, c1 - } - rr.Nsap = s - return rr, nil, c1 -} - -func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(GPOS) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, "" - } - _, e := strconv.ParseFloat(l.token, 64) - if e != nil { - return nil, &ParseError{f, "bad GPOS Longitude", l}, "" - } - rr.Longitude = l.token - <-c // zBlank - l = <-c - _, e = strconv.ParseFloat(l.token, 64) - if e != nil { - return nil, &ParseError{f, "bad GPOS Latitude", l}, "" - } - rr.Latitude = l.token - <-c // zBlank - l = <-c - _, e = strconv.ParseFloat(l.token, 64) - if e != nil { - return nil, &ParseError{f, "bad GPOS Altitude", l}, "" - } - rr.Altitude = l.token - return rr, nil, "" -} - -func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) { - rr := new(DS) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, "" - } - rr.KeyTag = uint16(i) - <-c // zBlank - l = <-c - if i, e := strconv.Atoi(l.token); e != nil { - i, ok := StringToAlgorithm[l.tokenUpper] - if !ok { - return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" - } - rr.Algorithm = i - } else { - rr.Algorithm = uint8(i) - } - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad " + typ + " DigestType", l}, "" - } - rr.DigestType = uint8(i) - s, e1, c1 := endingToString(c, "bad "+typ+" Digest", f) - if e1 != nil { - return nil, e1, c1 - } - rr.Digest = s - return rr, nil, c1 -} - -func setDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDSs(h, c, o, f, "DS") - return r, e, s -} - -func setDLV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDSs(h, c, o, f, "DLV") - if r != nil { - return &DLV{*r.(*DS)}, e, s - } - return nil, e, s -} - -func setCDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDSs(h, c, o, f, "CDS") - if r != nil { - return &CDS{*r.(*DS)}, e, s - } - return nil, e, s -} - -func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(TA) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad TA KeyTag", l}, "" - } - rr.KeyTag = uint16(i) - <-c // zBlank - l = <-c - if i, e := strconv.Atoi(l.token); e != nil { - i, ok := StringToAlgorithm[l.tokenUpper] - if !ok { - return nil, &ParseError{f, "bad TA Algorithm", l}, "" - } - rr.Algorithm = i - } else { - rr.Algorithm = uint8(i) - } - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad TA DigestType", l}, "" - } - rr.DigestType = uint8(i) - s, e, c1 := endingToString(c, "bad TA Digest", f) - if e != nil { - return nil, e.(*ParseError), c1 - } - rr.Digest = s - return rr, nil, c1 -} - -func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(TLSA) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad TLSA Usage", l}, "" - } - rr.Usage = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad TLSA Selector", l}, "" - } - rr.Selector = uint8(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad TLSA MatchingType", l}, "" - } - rr.MatchingType = uint8(i) - s, e, c1 := endingToString(c, "bad TLSA Certificate", f) - if e != nil { - return nil, e.(*ParseError), c1 - } - rr.Certificate = s - return rr, nil, c1 -} - -func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(RFC3597) - rr.Hdr = h - l := <-c - if l.token != "\\#" { - return nil, &ParseError{f, "bad RFC3597 Rdata", l}, "" - } - <-c // zBlank - l = <-c - rdlength, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, "" - } - - s, e1, c1 := endingToString(c, "bad RFC3597 Rdata", f) - if e1 != nil { - return nil, e1, c1 - } - if rdlength*2 != len(s) { - return nil, &ParseError{f, "bad RFC3597 Rdata", l}, "" - } - rr.Rdata = s - return rr, nil, c1 -} - -func setSPF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(SPF) - rr.Hdr = h - - s, e, c1 := endingToTxtSlice(c, "bad SPF Txt", f) - if e != nil { - return nil, e, "" - } - rr.Txt = s - return rr, nil, c1 -} - -func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(TXT) - rr.Hdr = h - - // no zBlank reading here, because all this rdata is TXT - s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f) - if e != nil { - return nil, e, "" - } - rr.Txt = s - return rr, nil, c1 -} - -// identical to setTXT -func setNINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NINFO) - rr.Hdr = h - - s, e, c1 := endingToTxtSlice(c, "bad NINFO ZSData", f) - if e != nil { - return nil, e, "" - } - rr.ZSData = s - return rr, nil, c1 -} - -func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(URI) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad URI Priority", l}, "" - } - rr.Priority = uint16(i) - <-c // zBlank - l = <-c - i, e = strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad URI Weight", l}, "" - } - rr.Weight = uint16(i) - - <-c // zBlank - s, e, c1 := endingToTxtSlice(c, "bad URI Target", f) - if e != nil { - return nil, e.(*ParseError), "" - } - rr.Target = s - return rr, nil, c1 -} - -func setDHCID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - // awesome record to parse! - rr := new(DHCID) - rr.Hdr = h - - s, e, c1 := endingToString(c, "bad DHCID Digest", f) - if e != nil { - return nil, e, c1 - } - rr.Digest = s - return rr, nil, c1 -} - -func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NID) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NID Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - u, err := stringToNodeID(l) - if err != nil { - return nil, err, "" - } - rr.NodeID = u - return rr, nil, "" -} - -func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(L32) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad L32 Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Locator32 = net.ParseIP(l.token) - if rr.Locator32 == nil { - return nil, &ParseError{f, "bad L32 Locator", l}, "" - } - return rr, nil, "" -} - -func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(LP) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad LP Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Fqdn = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Fqdn = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad LP Fqdn", l}, "" - } - if rr.Fqdn[l.length-1] != '.' { - rr.Fqdn = appendOrigin(rr.Fqdn, o) - } - return rr, nil, "" -} - -func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(L64) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad L64 Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - u, err := stringToNodeID(l) - if err != nil { - return nil, err, "" - } - rr.Locator64 = u - return rr, nil, "" -} - -func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(UID) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad UID Uid", l}, "" - } - rr.Uid = uint32(i) - return rr, nil, "" -} - -func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(GID) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad GID Gid", l}, "" - } - rr.Gid = uint32(i) - return rr, nil, "" -} - -func setUINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(UINFO) - rr.Hdr = h - s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f) - if e != nil { - return nil, e, "" - } - rr.Uinfo = s[0] // silently discard anything above - return rr, nil, c1 -} - -func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(PX) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, "" - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad PX Preference", l}, "" - } - rr.Preference = uint16(i) - <-c // zBlank - l = <-c // zString - rr.Map822 = l.token - if l.length == 0 { - return rr, nil, "" - } - if l.token == "@" { - rr.Map822 = o - return rr, nil, "" - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad PX Map822", l}, "" - } - if rr.Map822[l.length-1] != '.' { - rr.Map822 = appendOrigin(rr.Map822, o) - } - <-c // zBlank - l = <-c // zString - rr.Mapx400 = l.token - if l.token == "@" { - rr.Mapx400 = o - return rr, nil, "" - } - _, ok = IsDomainName(l.token) - if !ok || l.length == 0 { - return nil, &ParseError{f, "bad PX Mapx400", l}, "" - } - if rr.Mapx400[l.length-1] != '.' { - rr.Mapx400 = appendOrigin(rr.Mapx400, o) - } - return rr, nil, "" -} - -func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(IPSECKEY) - rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, err := strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, "" - } - rr.Precedence = uint8(i) - <-c // zBlank - l = <-c - i, err = strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, "" - } - rr.GatewayType = uint8(i) - <-c // zBlank - l = <-c - i, err = strconv.Atoi(l.token) - if err != nil { - return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, "" - } - rr.Algorithm = uint8(i) - - // Now according to GatewayType we can have different elements here - <-c // zBlank - l = <-c - switch rr.GatewayType { - case 0: - fallthrough - case 3: - rr.GatewayName = l.token - if l.token == "@" { - rr.GatewayName = o - } - _, ok := IsDomainName(l.token) - if !ok { - return nil, &ParseError{f, "bad IPSECKEY GatewayName", l}, "" - } - if rr.GatewayName[l.length-1] != '.' { - rr.GatewayName = appendOrigin(rr.GatewayName, o) - } - case 1: - rr.GatewayA = net.ParseIP(l.token) - if rr.GatewayA == nil { - return nil, &ParseError{f, "bad IPSECKEY GatewayA", l}, "" - } - case 2: - rr.GatewayAAAA = net.ParseIP(l.token) - if rr.GatewayAAAA == nil { - return nil, &ParseError{f, "bad IPSECKEY GatewayAAAA", l}, "" - } - default: - return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, "" - } - - s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f) - if e != nil { - return nil, e, c1 - } - rr.PublicKey = s - return rr, nil, c1 -} - -var typeToparserFunc = map[uint16]parserFunc{ - TypeAAAA: parserFunc{setAAAA, false}, - TypeAFSDB: parserFunc{setAFSDB, false}, - TypeA: parserFunc{setA, false}, - TypeCDS: parserFunc{setCDS, true}, - TypeCDNSKEY: parserFunc{setCDNSKEY, true}, - TypeCERT: parserFunc{setCERT, true}, - TypeCNAME: parserFunc{setCNAME, false}, - TypeDHCID: parserFunc{setDHCID, true}, - TypeDLV: parserFunc{setDLV, true}, - TypeDNAME: parserFunc{setDNAME, false}, - TypeKEY: parserFunc{setKEY, true}, - TypeDNSKEY: parserFunc{setDNSKEY, true}, - TypeDS: parserFunc{setDS, true}, - TypeEID: parserFunc{setEID, true}, - TypeEUI48: parserFunc{setEUI48, false}, - TypeEUI64: parserFunc{setEUI64, false}, - TypeGID: parserFunc{setGID, false}, - TypeGPOS: parserFunc{setGPOS, false}, - TypeHINFO: parserFunc{setHINFO, false}, - TypeHIP: parserFunc{setHIP, true}, - TypeIPSECKEY: parserFunc{setIPSECKEY, true}, - TypeKX: parserFunc{setKX, false}, - TypeL32: parserFunc{setL32, false}, - TypeL64: parserFunc{setL64, false}, - TypeLOC: parserFunc{setLOC, true}, - TypeLP: parserFunc{setLP, false}, - TypeMB: parserFunc{setMB, false}, - TypeMD: parserFunc{setMD, false}, - TypeMF: parserFunc{setMF, false}, - TypeMG: parserFunc{setMG, false}, - TypeMINFO: parserFunc{setMINFO, false}, - TypeMR: parserFunc{setMR, false}, - TypeMX: parserFunc{setMX, false}, - TypeNAPTR: parserFunc{setNAPTR, false}, - TypeNID: parserFunc{setNID, false}, - TypeNIMLOC: parserFunc{setNIMLOC, true}, - TypeNINFO: parserFunc{setNINFO, true}, - TypeNSAP: parserFunc{setNSAP, true}, - TypeNSAPPTR: parserFunc{setNSAPPTR, false}, - TypeNSEC3PARAM: parserFunc{setNSEC3PARAM, false}, - TypeNSEC3: parserFunc{setNSEC3, true}, - TypeNSEC: parserFunc{setNSEC, true}, - TypeNS: parserFunc{setNS, false}, - TypeOPENPGPKEY: parserFunc{setOPENPGPKEY, true}, - TypePTR: parserFunc{setPTR, false}, - TypePX: parserFunc{setPX, false}, - TypeSIG: parserFunc{setSIG, true}, - TypeRKEY: parserFunc{setRKEY, true}, - TypeRP: parserFunc{setRP, false}, - TypeRRSIG: parserFunc{setRRSIG, true}, - TypeRT: parserFunc{setRT, false}, - TypeSOA: parserFunc{setSOA, false}, - TypeSPF: parserFunc{setSPF, true}, - TypeSRV: parserFunc{setSRV, false}, - TypeSSHFP: parserFunc{setSSHFP, false}, - TypeTALINK: parserFunc{setTALINK, false}, - TypeTA: parserFunc{setTA, true}, - TypeTLSA: parserFunc{setTLSA, true}, - TypeTXT: parserFunc{setTXT, true}, - TypeUID: parserFunc{setUID, false}, - TypeUINFO: parserFunc{setUINFO, true}, - TypeURI: parserFunc{setURI, true}, - TypeWKS: parserFunc{setWKS, true}, - TypeX25: parserFunc{setX25, false}, -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gitignore b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gitignore deleted file mode 100644 index 1377554eb..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.swp diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gxlastpubver b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gxlastpubver deleted file mode 100644 index b91cdc721..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/.gxlastpubver +++ /dev/null @@ -1 +0,0 @@ -QmYmW76Y7NxvWwW3GPUmpbHd4mm1iW14f5UimeJ9UoofEs \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/README.md b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/README.md deleted file mode 100644 index 8b9cd9504..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# go-multiplex - -A super simple stream muxing library compatible with [multiplex](http://github.com/maxogden/multiplex) - -## Usage - -```go -mplex := multiplex.NewMultiplex(mysocket) - -s := mplex.NewStream() -s.Write([]byte("Hello World!") -s.Close() - -mplex.Serve(func(s *multiplex.Stream) { - // echo back everything received - io.Copy(s, s) -}) -``` diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex.go deleted file mode 100644 index 01b2dc1c5..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex.go +++ /dev/null @@ -1,393 +0,0 @@ -package multiplex - -import ( - "bufio" - "encoding/binary" - "errors" - "fmt" - "io" - "io/ioutil" - "sync" -) - -const ( - NewStream = iota - Receiver - Initiator - Unknown - Close -) - -var _ = ioutil.ReadAll -var _ = bufio.NewReadWriter -var _ = binary.MaxVarintLen16 - -type msg struct { - header uint64 - data []byte - err chan<- error -} - -type Stream struct { - id uint64 - name string - header uint64 - closed chan struct{} - data_in chan []byte - data_out chan<- msg - extra []byte -} - -func newStream(id uint64, name string, initiator bool, send chan<- msg) *Stream { - var hfn uint64 - if initiator { - hfn = 2 - } else { - hfn = 1 - } - return &Stream{ - id: id, - name: name, - header: (id << 3) | hfn, - data_in: make(chan []byte, 8), - data_out: send, - closed: make(chan struct{}), - } -} - -func (s *Stream) Name() string { - return s.name -} - -func (s *Stream) receive(b []byte) { - select { - case s.data_in <- b: - case <-s.closed: - } -} - -func (m *Multiplex) Accept() (*Stream, error) { - select { - case s, ok := <-m.nstreams: - if !ok { - return nil, errors.New("multiplex closed") - } - return s, nil - case err := <-m.errs: - return nil, err - case <-m.closed: - return nil, errors.New("multiplex closed") - } -} - -func (s *Stream) Read(b []byte) (int, error) { - if s.extra == nil { - select { - case <-s.closed: - return 0, io.EOF - case read, ok := <-s.data_in: - if !ok { - return 0, io.EOF - } - s.extra = read - } - } - n := copy(b, s.extra) - if n < len(s.extra) { - s.extra = s.extra[n:] - } else { - s.extra = nil - } - return n, nil -} - -func (s *Stream) Write(b []byte) (int, error) { - errs := make(chan error, 1) - select { - case s.data_out <- msg{header: s.header, data: b, err: errs}: - select { - case err := <-errs: - return len(b), err - case <-s.closed: - return 0, errors.New("stream closed") - } - - case <-s.closed: - return 0, errors.New("stream closed") - } -} - -func (s *Stream) Close() error { - select { - case <-s.closed: - return nil - default: - close(s.closed) - select { - case s.data_out <- msg{ - header: (s.id << 3) | Close, - err: make(chan error, 1), //throw away error, whatever - }: - default: - } - close(s.data_in) - return nil - } -} - -type Multiplex struct { - con io.ReadWriteCloser - buf *bufio.Reader - nextID uint64 - outchan chan msg - closed chan struct{} - initiator bool - - nstreams chan *Stream - errs chan error - - channels map[uint64]*Stream - ch_lock sync.Mutex -} - -func NewMultiplex(con io.ReadWriteCloser, initiator bool) *Multiplex { - mp := &Multiplex{ - con: con, - initiator: initiator, - buf: bufio.NewReader(con), - channels: make(map[uint64]*Stream), - outchan: make(chan msg), - closed: make(chan struct{}), - nstreams: make(chan *Stream, 16), - errs: make(chan error), - } - - go mp.handleOutgoing() - go mp.handleIncoming() - - return mp -} - -func (mp *Multiplex) Close() error { - if mp.IsClosed() { - return nil - } - close(mp.closed) - mp.ch_lock.Lock() - defer mp.ch_lock.Unlock() - for _, s := range mp.channels { - err := s.Close() - if err != nil { - return err - } - } - return nil -} - -func (mp *Multiplex) IsClosed() bool { - select { - case <-mp.closed: - return true - default: - return false - } -} - -func (mp *Multiplex) handleOutgoing() { - for { - select { - case msg, ok := <-mp.outchan: - if !ok { - return - } - - buf := EncodeVarint(msg.header) - _, err := mp.con.Write(buf) - if err != nil { - msg.err <- err - continue - } - - buf = EncodeVarint(uint64(len(msg.data))) - _, err = mp.con.Write(buf) - if err != nil { - msg.err <- err - continue - } - - _, err = mp.con.Write(msg.data) - if err != nil { - msg.err <- err - continue - } - - msg.err <- nil - case <-mp.closed: - return - } - } -} - -func (mp *Multiplex) nextChanID() (out uint64) { - if mp.initiator { - out = mp.nextID + 1 - } else { - out = mp.nextID - } - mp.nextID += 2 - return -} - -func (mp *Multiplex) NewStream() *Stream { - return mp.NewNamedStream("") -} - -func (mp *Multiplex) NewNamedStream(name string) *Stream { - mp.ch_lock.Lock() - sid := mp.nextChanID() - header := (sid << 3) | NewStream - - if name == "" { - name = fmt.Sprint(sid) - } - s := newStream(sid, name, true, mp.outchan) - mp.channels[sid] = s - mp.ch_lock.Unlock() - - mp.outchan <- msg{ - header: header, - data: []byte(name), - err: make(chan error, 1), //throw away error - } - - return s -} - -func (mp *Multiplex) sendErr(err error) { - select { - case mp.errs <- err: - case <-mp.closed: - } -} - -func (mp *Multiplex) handleIncoming() { - defer mp.shutdown() - for { - ch, tag, err := mp.readNextHeader() - if err != nil { - mp.sendErr(err) - return - } - - b, err := mp.readNext() - if err != nil { - mp.sendErr(err) - return - } - - mp.ch_lock.Lock() - msch, ok := mp.channels[ch] - if !ok { - var name string - if tag == NewStream { - name = string(b) - } - msch = newStream(ch, name, false, mp.outchan) - mp.channels[ch] = msch - select { - case mp.nstreams <- msch: - case <-mp.closed: - return - } - if tag == NewStream { - mp.ch_lock.Unlock() - continue - } - } - mp.ch_lock.Unlock() - - if tag == Close { - msch.Close() - mp.ch_lock.Lock() - delete(mp.channels, ch) - mp.ch_lock.Unlock() - continue - } - - msch.receive(b) - } -} - -func (mp *Multiplex) shutdown() { - mp.ch_lock.Lock() - defer mp.ch_lock.Unlock() - for _, s := range mp.channels { - s.Close() - } -} - -func (mp *Multiplex) readNextHeader() (uint64, uint64, error) { - h, _, err := DecodeVarint(mp.buf) - if err != nil { - return 0, 0, err - } - - // get channel ID - ch := h >> 3 - - rem := h & 7 - - return ch, rem, nil -} - -func (mp *Multiplex) readNext() ([]byte, error) { - // get length - l, _, err := DecodeVarint(mp.buf) - if err != nil { - return nil, err - } - - buf := make([]byte, l) - n, err := io.ReadFull(mp.buf, buf) - if err != nil { - return nil, err - } - - if n != int(l) { - panic("NOT THE SAME") - } - - return buf, nil -} - -func EncodeVarint(x uint64) []byte { - var buf [10]byte - var n int - for n = 0; x > 127; n++ { - buf[n] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - buf[n] = uint8(x) - n++ - return buf[0:n] -} - -func DecodeVarint(r *bufio.Reader) (x uint64, n int, err error) { - // x, n already 0 - for shift := uint(0); shift < 64; shift += 7 { - val, err := r.ReadByte() - if err != nil { - return 0, 0, err - } - - b := uint64(val) - n++ - x |= (b & 0x7F) << shift - if (b & 0x80) == 0 { - return x, n, nil - } - } - - // The number is too large to represent in a 64-bit value. - return 0, 0, errors.New("Too large of a number!") -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex_test.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex_test.go deleted file mode 100644 index f2b541a4c..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/multiplex_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package multiplex - -import ( - "fmt" - "io" - "net" - "testing" - - rand "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo" -) - -func TestBasicStreams(t *testing.T) { - a, b := net.Pipe() - - mpa := NewMultiplex(a, false) - mpb := NewMultiplex(b, true) - - mes := []byte("Hello world") - go func() { - s, err := mpb.Accept() - if err != nil { - t.Fatal(err) - } - - _, err = s.Write(mes) - if err != nil { - t.Fatal(err) - } - - err = s.Close() - if err != nil { - t.Fatal(err) - } - }() - - s := mpa.NewStream() - - buf := make([]byte, len(mes)) - n, err := s.Read(buf) - if err != nil { - t.Fatal(err) - } - - if n != len(mes) { - t.Fatal("read wrong amount") - } - - if string(buf) != string(mes) { - t.Fatal("got bad data") - } - - s.Close() - - mpa.Close() - mpb.Close() -} - -func TestEcho(t *testing.T) { - a, b := net.Pipe() - - mpa := NewMultiplex(a, false) - mpb := NewMultiplex(b, true) - - mes := make([]byte, 40960) - rand.New().Read(mes) - go func() { - s, err := mpb.Accept() - if err != nil { - t.Fatal(err) - } - - defer s.Close() - io.Copy(s, s) - }() - - s := mpa.NewStream() - - _, err := s.Write(mes) - if err != nil { - t.Fatal(err) - } - - buf := make([]byte, len(mes)) - n, err := io.ReadFull(s, buf) - if err != nil { - t.Fatal(err) - } - - if n != len(mes) { - t.Fatal("read wrong amount") - } - - if err := arrComp(buf, mes); err != nil { - t.Fatal(err) - } - s.Close() - - mpa.Close() - mpb.Close() -} - -func arrComp(a, b []byte) error { - msg := "" - if len(a) != len(b) { - msg += fmt.Sprintf("arrays differ in length: %d %d\n", len(a), len(b)) - } - - for i := 0; i < len(a) && i < len(b); i++ { - if a[i] != b[i] { - msg += fmt.Sprintf("content differs at index %d [%d != %d]", i, a[i], b[i]) - return fmt.Errorf(msg) - } - } - if len(msg) > 0 { - return fmt.Errorf(msg) - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/package.json b/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/package.json deleted file mode 100644 index 9b0e7000a..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multiplex/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "go-multiplex", - "version": "1.0.0", - "language": "go" -} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/README.md b/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/README.md deleted file mode 100644 index 1ade9dc60..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/README.md +++ /dev/null @@ -1,43 +0,0 @@ -#Multistream-select router -This package implements a simple stream router for the multistream-select protocol. -The protocol is defined [here](https://github.com/jbenet/multistream). - - -Usage: - -```go -package main - -import ( - "fmt" - ms "github.com/whyrusleeping/go-multistream" - "io" - "net" -) - -func main() { - mux := ms.NewMultistreamMuxer() - mux.AddHandler("/cats", func(rwc io.ReadWriteCloser) error { - fmt.Fprintln(rwc, "HELLO I LIKE CATS") - return rwc.Close() - }) - mux.AddHandler("/dogs", func(rwc io.ReadWriteCloser) error { - fmt.Fprintln(rwc, "HELLO I LIKE DOGS") - return rwc.Close() - }) - - list, err := net.Listen("tcp", ":8765") - if err != nil { - panic(err) - } - - for { - con, err := list.Accept() - if err != nil { - panic(err) - } - - go mux.Handle(con) - } -} -``` diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/client.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/client.go deleted file mode 100644 index 622fa3b10..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/client.go +++ /dev/null @@ -1,75 +0,0 @@ -package multistream - -import ( - "errors" - "io" -) - -var ErrNotSupported = errors.New("protocol not supported") - -func SelectProtoOrFail(proto string, rwc io.ReadWriteCloser) error { - err := handshake(rwc) - if err != nil { - return err - } - - return trySelect(proto, rwc) -} - -func SelectOneOf(protos []string, rwc io.ReadWriteCloser) (string, error) { - err := handshake(rwc) - if err != nil { - return "", err - } - - for _, p := range protos { - err := trySelect(p, rwc) - switch err { - case nil: - return p, nil - case ErrNotSupported: - default: - return "", err - } - } - return "", ErrNotSupported -} - -func handshake(rwc io.ReadWriteCloser) error { - tok, err := ReadNextToken(rwc) - if err != nil { - return err - } - - if tok != ProtocolID { - return errors.New("received mismatch in protocol id") - } - - err = delimWrite(rwc, []byte(ProtocolID)) - if err != nil { - return err - } - - return nil -} - -func trySelect(proto string, rwc io.ReadWriteCloser) error { - err := delimWrite(rwc, []byte(proto)) - if err != nil { - return err - } - - tok, err := ReadNextToken(rwc) - if err != nil { - return err - } - - switch tok { - case proto: - return nil - case "na": - return ErrNotSupported - default: - return errors.New("unrecognized response: " + tok) - } -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/lazy.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/lazy.go deleted file mode 100644 index e86296a76..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/lazy.go +++ /dev/null @@ -1,124 +0,0 @@ -package multistream - -import ( - "fmt" - "io" - "sync" -) - -type Multistream interface { - io.ReadWriteCloser - Protocol() string -} - -func NewMSSelect(c io.ReadWriteCloser, proto string) Multistream { - return NewMultistream(NewMultistream(c, ProtocolID), proto) -} - -func NewMultistream(c io.ReadWriteCloser, proto string) Multistream { - return &lazyConn{ - proto: proto, - con: c, - } -} - -type lazyConn struct { - rhandshake bool // only accessed by 'Read' should not call read async - - rhlock sync.Mutex - rhsync bool //protected by mutex - rerr error - - whandshake bool - - whlock sync.Mutex - whsync bool - werr error - - proto string - con io.ReadWriteCloser -} - -func (l *lazyConn) Protocol() string { - return l.proto -} - -func (l *lazyConn) Read(b []byte) (int, error) { - if !l.rhandshake { - go l.writeHandshake() - err := l.readHandshake() - if err != nil { - return 0, err - } - - l.rhandshake = true - } - - if len(b) == 0 { - return 0, nil - } - - return l.con.Read(b) -} - -func (l *lazyConn) readHandshake() error { - l.rhlock.Lock() - defer l.rhlock.Unlock() - - // if we've already done this, exit - if l.rhsync { - return l.rerr - } - l.rhsync = true - - // read protocol - tok, err := ReadNextToken(l.con) - if err != nil { - l.rerr = err - return err - } - - if tok != l.proto { - l.rerr = fmt.Errorf("protocol mismatch in lazy handshake ( %s != %s )", tok, l.proto) - return l.rerr - } - - return nil -} - -func (l *lazyConn) writeHandshake() error { - l.whlock.Lock() - defer l.whlock.Unlock() - - if l.whsync { - return l.werr - } - - l.whsync = true - - err := delimWrite(l.con, []byte(l.proto)) - if err != nil { - l.werr = err - return err - } - - return nil -} - -func (l *lazyConn) Write(b []byte) (int, error) { - if !l.whandshake { - go l.readHandshake() - err := l.writeHandshake() - if err != nil { - return 0, err - } - - l.whandshake = true - } - - return l.con.Write(b) -} - -func (l *lazyConn) Close() error { - return l.con.Close() -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream.go deleted file mode 100644 index ecec8df73..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream.go +++ /dev/null @@ -1,201 +0,0 @@ -package multistream - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "sync" -) - -var ErrTooLarge = errors.New("incoming message was too large") - -const ProtocolID = "/multistream/1.0.0" - -type HandlerFunc func(io.ReadWriteCloser) error - -type MultistreamMuxer struct { - handlerlock sync.Mutex - handlers map[string]HandlerFunc -} - -func NewMultistreamMuxer() *MultistreamMuxer { - return &MultistreamMuxer{handlers: make(map[string]HandlerFunc)} -} - -func writeUvarint(w io.Writer, i uint64) error { - varintbuf := make([]byte, 32) - n := binary.PutUvarint(varintbuf, i) - _, err := w.Write(varintbuf[:n]) - if err != nil { - return err - } - return nil -} - -func delimWrite(w io.Writer, mes []byte) error { - err := writeUvarint(w, uint64(len(mes)+1)) - if err != nil { - return err - } - - _, err = w.Write(mes) - if err != nil { - return err - } - - _, err = w.Write([]byte{'\n'}) - if err != nil { - return err - } - return nil -} - -func (msm *MultistreamMuxer) AddHandler(protocol string, handler HandlerFunc) { - msm.handlerlock.Lock() - msm.handlers[protocol] = handler - msm.handlerlock.Unlock() -} - -func (msm *MultistreamMuxer) RemoveHandler(protocol string) { - msm.handlerlock.Lock() - delete(msm.handlers, protocol) - msm.handlerlock.Unlock() -} - -func (msm *MultistreamMuxer) Protocols() []string { - var out []string - msm.handlerlock.Lock() - for k, _ := range msm.handlers { - out = append(out, k) - } - msm.handlerlock.Unlock() - return out -} - -func (msm *MultistreamMuxer) Negotiate(rwc io.ReadWriteCloser) (string, HandlerFunc, error) { - // Send our protocol ID - err := delimWrite(rwc, []byte(ProtocolID)) - if err != nil { - return "", nil, err - } - - line, err := ReadNextToken(rwc) - if err != nil { - return "", nil, err - } - - if line != ProtocolID { - rwc.Close() - return "", nil, errors.New("client connected with incorrect version") - } - -loop: - for { - // Now read and respond to commands until they send a valid protocol id - tok, err := ReadNextToken(rwc) - if err != nil { - return "", nil, err - } - - switch tok { - case "ls": - err := msm.Ls(rwc) - if err != nil { - return "", nil, err - } - default: - msm.handlerlock.Lock() - h, ok := msm.handlers[tok] - msm.handlerlock.Unlock() - if !ok { - err := delimWrite(rwc, []byte("na")) - if err != nil { - return "", nil, err - } - continue loop - } - - err := delimWrite(rwc, []byte(tok)) - if err != nil { - return "", nil, err - } - - // hand off processing to the sub-protocol handler - return tok, h, nil - } - } - -} - -func (msm *MultistreamMuxer) Ls(rwc io.Writer) error { - buf := new(bytes.Buffer) - msm.handlerlock.Lock() - for proto, _ := range msm.handlers { - err := delimWrite(buf, []byte(proto)) - if err != nil { - msm.handlerlock.Unlock() - return err - } - } - msm.handlerlock.Unlock() - err := delimWrite(rwc, buf.Bytes()) - if err != nil { - return err - } - return nil -} - -func (msm *MultistreamMuxer) Handle(rwc io.ReadWriteCloser) error { - _, h, err := msm.Negotiate(rwc) - if err != nil { - return err - } - return h(rwc) -} - -func ReadNextToken(rw io.ReadWriter) (string, error) { - br := &byteReader{rw} - length, err := binary.ReadUvarint(br) - if err != nil { - return "", err - } - - if length > 64*1024 { - err := delimWrite(rw, []byte("messages over 64k are not allowed")) - if err != nil { - return "", err - } - return "", ErrTooLarge - } - - buf := make([]byte, length) - _, err = io.ReadFull(rw, buf) - if err != nil { - return "", err - } - - if len(buf) == 0 || buf[length-1] != '\n' { - return "", errors.New("message did not have trailing newline") - } - - // slice off the trailing newline - buf = buf[:length-1] - - return string(buf), nil -} - -// byteReader implements the ByteReader interface that ReadUVarint requires -type byteReader struct { - io.Reader -} - -func (br *byteReader) ReadByte() (byte, error) { - var b [1]byte - _, err := br.Read(b[:]) - - if err != nil { - return 0, err - } - return b[0], nil -} diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream_test.go b/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream_test.go deleted file mode 100644 index aaf0f7f57..000000000 --- a/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream/multistream_test.go +++ /dev/null @@ -1,259 +0,0 @@ -package multistream - -import ( - "crypto/rand" - "io" - "net" - "testing" - "time" -) - -func TestProtocolNegotiation(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - done := make(chan struct{}) - go func() { - selected, _, err := mux.Negotiate(a) - if err != nil { - t.Fatal(err) - } - if selected != "/a" { - t.Fatal("incorrect protocol selected") - } - close(done) - }() - - err := SelectProtoOrFail("/a", b) - if err != nil { - t.Fatal(err) - } - - select { - case <-time.After(time.Second): - t.Fatal("protocol negotiation didnt complete") - case <-done: - } - - verifyPipe(t, a, b) -} - -func TestSelectOne(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - done := make(chan struct{}) - go func() { - selected, _, err := mux.Negotiate(a) - if err != nil { - t.Fatal(err) - } - if selected != "/c" { - t.Fatal("incorrect protocol selected") - } - close(done) - }() - - sel, err := SelectOneOf([]string{"/d", "/e", "/c"}, b) - if err != nil { - t.Fatal(err) - } - - if sel != "/c" { - t.Fatal("selected wrong protocol") - } - - select { - case <-time.After(time.Second): - t.Fatal("protocol negotiation didnt complete") - case <-done: - } - - verifyPipe(t, a, b) -} - -func TestSelectOneAndWrite(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - done := make(chan struct{}) - go func() { - selected, _, err := mux.Negotiate(a) - if err != nil { - t.Fatal(err) - } - if selected != "/c" { - t.Fatal("incorrect protocol selected") - } - close(done) - }() - - sel, err := SelectOneOf([]string{"/d", "/e", "/c"}, b) - if err != nil { - t.Fatal(err) - } - - if sel != "/c" { - t.Fatal("selected wrong protocol") - } - - select { - case <-time.After(time.Second): - t.Fatal("protocol negotiation didnt complete") - case <-done: - } - - verifyPipe(t, a, b) -} - -func TestLazyConns(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - la := NewMSSelect(a, "/c") - lb := NewMSSelect(b, "/c") - - verifyPipe(t, la, lb) -} - -func TestLazyAndMux(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - done := make(chan struct{}) - go func() { - selected, _, err := mux.Negotiate(a) - if err != nil { - t.Fatal(err) - } - if selected != "/c" { - t.Fatal("incorrect protocol selected") - } - - msg := make([]byte, 5) - _, err = a.Read(msg) - if err != nil { - t.Fatal(err) - } - - close(done) - }() - - lb := NewMSSelect(b, "/c") - - // do a write to push the handshake through - _, err := lb.Write([]byte("hello")) - if err != nil { - t.Fatal(err) - } - - select { - case <-time.After(time.Second): - t.Fatal("failed to complete in time") - case <-done: - } - - verifyPipe(t, a, lb) -} - -func TestLazyAndMuxWrite(t *testing.T) { - a, b := net.Pipe() - - mux := NewMultistreamMuxer() - mux.AddHandler("/a", nil) - mux.AddHandler("/b", nil) - mux.AddHandler("/c", nil) - - done := make(chan struct{}) - go func() { - selected, _, err := mux.Negotiate(a) - if err != nil { - t.Fatal(err) - } - if selected != "/c" { - t.Fatal("incorrect protocol selected") - } - - _, err = a.Write([]byte("hello")) - if err != nil { - t.Fatal(err) - } - - close(done) - }() - - lb := NewMSSelect(b, "/c") - - // do a write to push the handshake through - msg := make([]byte, 5) - _, err := lb.Read(msg) - if err != nil { - t.Fatal(err) - } - - if string(msg) != "hello" { - t.Fatal("wrong!") - } - - select { - case <-time.After(time.Second): - t.Fatal("failed to complete in time") - case <-done: - } - - verifyPipe(t, a, lb) -} - -func verifyPipe(t *testing.T, a, b io.ReadWriter) { - mes := make([]byte, 1024) - rand.Read(mes) - go func() { - b.Write(mes) - a.Write(mes) - }() - - buf := make([]byte, len(mes)) - n, err := a.Read(buf) - if err != nil { - t.Fatal(err) - } - if n != len(buf) { - t.Fatal("failed to read enough") - } - - if string(buf) != string(mes) { - t.Fatal("somehow read wrong message") - } - - n, err = b.Read(buf) - if err != nil { - t.Fatal(err) - } - if n != len(buf) { - t.Fatal("failed to read enough") - } - - if string(buf) != string(mes) { - t.Fatal("somehow read wrong message") - } -} diff --git a/test/dependencies/iptb/proc_unix.go b/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/proc_unix.go similarity index 90% rename from test/dependencies/iptb/proc_unix.go rename to Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/proc_unix.go index dc1ca1cda..910506246 100644 --- a/test/dependencies/iptb/proc_unix.go +++ b/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/proc_unix.go @@ -1,6 +1,5 @@ // +build !windows - -package main +package iptbutil import ( "os/exec" diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/util.go b/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/util.go new file mode 100644 index 000000000..a1b4d9155 --- /dev/null +++ b/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util/util.go @@ -0,0 +1,542 @@ +package iptbutil + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path" + "strconv" + "strings" + "sync" + "syscall" + "time" + + serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize" + + manet "gx/ipfs/QmQB7mNP3QE7b4zP2MQmsyJDqG5hzYE2CL8k1VyLWky2Ed/go-multiaddr-net" + ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr" +) + +var setupOpt = func(cmd *exec.Cmd) {} + +// GetNumNodes returns the number of testbed nodes configured in the testbed directory +func GetNumNodes() int { + for i := 0; i < 2000; i++ { + _, err := os.Stat(IpfsDirN(i)) + if os.IsNotExist(err) { + return i + } + } + panic("i dont know whats going on") +} + +func TestBedDir() string { + tbd := os.Getenv("IPTB_ROOT") + if len(tbd) != 0 { + return tbd + } + + home := os.Getenv("HOME") + if len(home) == 0 { + panic("could not find home") + } + + return path.Join(home, "testbed") +} + +func IpfsDirN(n int) string { + return path.Join(TestBedDir(), fmt.Sprint(n)) +} + +type InitCfg struct { + Count int + Force bool + Bootstrap string + PortStart int + Mdns bool + Utp bool + Override string +} + +func (c *InitCfg) swarmAddrForPeer(i int) string { + str := "/ip4/0.0.0.0/tcp/%d" + if c.Utp { + str = "/ip4/0.0.0.0/udp/%d/utp" + } + + if c.PortStart == 0 { + return fmt.Sprintf(str, 0) + } + return fmt.Sprintf(str, c.PortStart+i) +} + +func (c *InitCfg) apiAddrForPeer(i int) string { + if c.PortStart == 0 { + return "/ip4/127.0.0.1/tcp/0" + } + return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.PortStart+1000+i) +} + +func YesNoPrompt(prompt string) bool { + var s string + for { + fmt.Println(prompt) + fmt.Scanf("%s", &s) + switch s { + case "y", "Y": + return true + case "n", "N": + return false + } + fmt.Println("Please press either 'y' or 'n'") + } +} + +func IpfsInit(cfg *InitCfg) error { + p := IpfsDirN(0) + if _, err := os.Stat(p); !os.IsNotExist(err) { + if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") { + return nil + } + err := os.RemoveAll(TestBedDir()) + if err != nil { + return err + } + } + wait := sync.WaitGroup{} + for i := 0; i < cfg.Count; i++ { + wait.Add(1) + go func(v int) { + defer wait.Done() + dir := IpfsDirN(v) + err := os.MkdirAll(dir, 0777) + if err != nil { + log.Println("ERROR: ", err) + return + } + + cmd := exec.Command("ipfs", "init", "-b=1024") + cmd.Env = append(cmd.Env, "IPFS_PATH="+dir) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println("ERROR: ", err) + log.Println(string(out)) + } + }(i) + } + wait.Wait() + + // Now setup bootstrapping + switch cfg.Bootstrap { + case "star": + err := starBootstrap(cfg) + if err != nil { + return err + } + case "none": + err := clearBootstrapping(cfg) + if err != nil { + return err + } + default: + return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap) + } + + /* + if cfg.Override != "" { + err := ApplyConfigOverride(cfg) + if err != nil { + return err + } + } + */ + + return nil +} + +func ApplyConfigOverride(cfg *InitCfg) error { + fir, err := os.Open(cfg.Override) + if err != nil { + return err + } + defer fir.Close() + + var configs map[string]interface{} + err = json.NewDecoder(fir).Decode(&configs) + if err != nil { + return err + } + + for i := 0; i < cfg.Count; i++ { + err := applyOverrideToNode(configs, i) + if err != nil { + return err + } + } + + return nil +} + +func applyOverrideToNode(ovr map[string]interface{}, node int) error { + for k, v := range ovr { + _ = k + switch v.(type) { + case map[string]interface{}: + default: + } + + } + + panic("not implemented") +} + +func starBootstrap(icfg *InitCfg) error { + // '0' node is the bootstrap node + cfgpath := path.Join(IpfsDirN(0), "config") + bcfg, err := serial.Load(cfgpath) + if err != nil { + return err + } + bcfg.Bootstrap = nil + bcfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(0)} + bcfg.Addresses.API = icfg.apiAddrForPeer(0) + bcfg.Addresses.Gateway = "" + bcfg.Discovery.MDNS.Enabled = icfg.Mdns + err = serial.WriteConfigFile(cfgpath, bcfg) + if err != nil { + return err + } + + for i := 1; i < icfg.Count; i++ { + cfgpath := path.Join(IpfsDirN(i), "config") + cfg, err := serial.Load(cfgpath) + if err != nil { + return err + } + + ba := fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID) + ba = strings.Replace(ba, "0.0.0.0", "127.0.0.1", -1) + cfg.Bootstrap = []string{ba} + cfg.Addresses.Gateway = "" + cfg.Discovery.MDNS.Enabled = icfg.Mdns + cfg.Addresses.Swarm = []string{ + icfg.swarmAddrForPeer(i), + } + cfg.Addresses.API = icfg.apiAddrForPeer(i) + err = serial.WriteConfigFile(cfgpath, cfg) + if err != nil { + return err + } + } + return nil +} + +func clearBootstrapping(icfg *InitCfg) error { + for i := 0; i < icfg.Count; i++ { + cfgpath := path.Join(IpfsDirN(i), "config") + cfg, err := serial.Load(cfgpath) + if err != nil { + return err + } + + cfg.Bootstrap = nil + cfg.Addresses.Gateway = "" + cfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(i)} + cfg.Addresses.API = icfg.apiAddrForPeer(i) + cfg.Discovery.MDNS.Enabled = icfg.Mdns + err = serial.WriteConfigFile(cfgpath, cfg) + if err != nil { + return err + } + } + return nil +} + +func IpfsPidOf(n int) (int, error) { + dir := IpfsDirN(n) + b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid")) + if err != nil { + return -1, err + } + + return strconv.Atoi(string(b)) +} + +func KillNode(i int) error { + pid, err := IpfsPidOf(i) + if err != nil { + return fmt.Errorf("error killing daemon %d: %s", i, err) + } + + p, err := os.FindProcess(pid) + if err != nil { + return fmt.Errorf("error killing daemon %d: %s", i, err) + } + err = p.Kill() + if err != nil { + return fmt.Errorf("error killing daemon %d: %s\n", i, err) + } + + p.Wait() + + err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid")) + if err != nil { + return fmt.Errorf("error removing pid file for daemon %d: %s\n", i, err) + } + + return nil +} + +func IpfsKillAll() error { + n := GetNumNodes() + for i := 0; i < n; i++ { + err := KillNode(i) + if err != nil { + return err + } + } + return nil +} + +func envForDaemon(n int) []string { + envs := os.Environ() + npath := "IPFS_PATH=" + IpfsDirN(n) + for i, e := range envs { + p := strings.Split(e, "=") + if p[0] == "IPFS_PATH" { + envs[i] = npath + return envs + } + } + + return append(envs, npath) +} + +func IpfsStart(waitall bool) error { + var addrs []string + n := GetNumNodes() + for i := 0; i < n; i++ { + dir := IpfsDirN(i) + cmd := exec.Command("ipfs", "daemon") + cmd.Dir = dir + cmd.Env = envForDaemon(i) + + setupOpt(cmd) + + stdout, err := os.Create(path.Join(dir, "daemon.stdout")) + if err != nil { + return err + } + + stderr, err := os.Create(path.Join(dir, "daemon.stderr")) + if err != nil { + return err + } + + cmd.Stdout = stdout + cmd.Stderr = stderr + + err = cmd.Start() + if err != nil { + return err + } + pid := cmd.Process.Pid + + fmt.Printf("Started daemon %d, pid = %d\n", i, pid) + err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666) + if err != nil { + return err + } + + // Make sure node 0 is up before starting the rest so + // bootstrapping works properly + cfg, err := serial.Load(path.Join(IpfsDirN(i), "config")) + if err != nil { + return err + } + + maddr := ma.StringCast(cfg.Addresses.API) + _, addr, err := manet.DialArgs(maddr) + if err != nil { + return err + } + + addrs = append(addrs, addr) + + err = waitOnAPI(cfg.Identity.PeerID, i) + if err != nil { + return err + } + } + if waitall { + for i := 0; i < n; i++ { + err := waitOnSwarmPeers(i) + if err != nil { + return err + } + } + + } + return nil +} + +func waitOnAPI(peerid string, nnum int) error { + for i := 0; i < 50; i++ { + err := tryAPICheck(peerid, nnum) + if err == nil { + return nil + } + time.Sleep(time.Millisecond * 200) + } + return fmt.Errorf("node %d failed to come online in given time period", nnum) +} + +func GetNodesAPIAddr(nnum int) (string, error) { + addrb, err := ioutil.ReadFile(path.Join(IpfsDirN(nnum), "api")) + if err != nil { + return "", err + } + + maddr, err := ma.NewMultiaddr(string(addrb)) + if err != nil { + fmt.Println("error parsing multiaddr: ", err) + return "", err + } + + _, addr, err := manet.DialArgs(maddr) + if err != nil { + fmt.Println("error on multiaddr dialargs: ", err) + return "", err + } + return addr, nil +} + +func tryAPICheck(peerid string, nnum int) error { + addr, err := GetNodesAPIAddr(nnum) + if err != nil { + return err + } + + resp, err := http.Get("http://" + addr + "/api/v0/id") + if err != nil { + return err + } + + out := make(map[string]interface{}) + err = json.NewDecoder(resp.Body).Decode(&out) + if err != nil { + return fmt.Errorf("liveness check failed: %s", err) + } + + id, ok := out["ID"] + if !ok { + return fmt.Errorf("liveness check failed: ID field not present in output") + } + + idstr := id.(string) + if idstr != peerid { + return fmt.Errorf("liveness check failed: unexpected peer at endpoint") + } + + return nil +} + +func waitOnSwarmPeers(nnum int) error { + addr, err := GetNodesAPIAddr(nnum) + if err != nil { + return err + } + + for i := 0; i < 50; i++ { + resp, err := http.Get("http://" + addr + "/api/v0/swarm/peers") + if err == nil { + out := make(map[string]interface{}) + err := json.NewDecoder(resp.Body).Decode(&out) + if err != nil { + return fmt.Errorf("liveness check failed: %s", err) + } + + peers := out["Strings"].([]interface{}) + if len(peers) == 0 { + time.Sleep(time.Millisecond * 200) + continue + } + + return nil + } + time.Sleep(time.Millisecond * 200) + } + return fmt.Errorf("node at %s failed to bootstrap in given time period", addr) +} + +// GetPeerID reads the config of node 'n' and returns its peer ID +func GetPeerID(n int) (string, error) { + cfg, err := serial.Load(path.Join(IpfsDirN(n), "config")) + if err != nil { + return "", err + } + return cfg.Identity.PeerID, nil +} + +// IpfsShell sets up environment variables for a new shell to more easily +// control the given daemon +func IpfsShell(n int) error { + shell := os.Getenv("SHELL") + if shell == "" { + return fmt.Errorf("couldnt find shell!") + } + + dir := IpfsDirN(n) + nenvs := []string{"IPFS_PATH=" + dir} + + nnodes := GetNumNodes() + for i := 0; i < nnodes; i++ { + peerid, err := GetPeerID(i) + if err != nil { + return err + } + nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid)) + } + nenvs = append(os.Environ(), nenvs...) + + return syscall.Exec(shell, []string{shell}, nenvs) +} + +func ConnectNodes(from, to int) error { + if from == to { + // skip connecting to self.. + return nil + } + fmt.Printf("connecting %d -> %d\n", from, to) + cmd := exec.Command("ipfs", "id", "-f", "") + cmd.Env = []string{"IPFS_PATH=" + IpfsDirN(to)} + out, err := cmd.Output() + if err != nil { + fmt.Println("ERR: ", string(out)) + return err + } + addr := strings.Split(string(out), "\n")[0] + + connectcmd := exec.Command("ipfs", "swarm", "connect", addr) + connectcmd.Env = []string{"IPFS_PATH=" + IpfsDirN(from)} + out, err = connectcmd.CombinedOutput() + if err != nil { + fmt.Println(string(out)) + return err + } + return nil +} + +func GetAttr(attr string, node int) (string, error) { + switch attr { + case "id": + return GetPeerID(node) + default: + return "", errors.New("unrecognized attribute") + } +} diff --git a/repo/fsrepo/datastores.go b/repo/fsrepo/datastores.go deleted file mode 100644 index 7ed608137..000000000 --- a/repo/fsrepo/datastores.go +++ /dev/null @@ -1,38 +0,0 @@ -package fsrepo - -import ( - "fmt" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/aws" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - - repo "github.com/ipfs/go-ipfs/repo" - config "github.com/ipfs/go-ipfs/repo/config" - "github.com/ipfs/go-ipfs/thirdparty/s3-datastore" -) - -func openS3Datastore(params config.S3Datastore) (repo.Datastore, error) { - // TODO support credentials files - auth, err := aws.EnvAuth() - if err != nil { - return nil, err - } - - region := aws.GetRegion(params.Region) - if region.Name == "" { - return nil, fmt.Errorf("unknown AWS region: %q", params.Region) - } - - if params.Bucket == "" { - return nil, fmt.Errorf("invalid S3 bucket: %q", params.Bucket) - } - - client := s3.New(auth, region) - // There are too many gophermucking s3datastores in my - // gophermucking source. - return &s3datastore.S3Datastore{ - Client: client, - Bucket: params.Bucket, - ACL: s3.ACL(params.ACL), - }, nil -} diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 0e21cfa6a..18580986d 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -1,7 +1,6 @@ package fsrepo import ( - "encoding/json" "errors" "fmt" "io" @@ -334,18 +333,6 @@ func (r *FSRepo) openDatastore() error { return err } r.ds = d - case "s3": - var dscfg config.S3Datastore - if err := json.Unmarshal(r.config.Datastore.ParamData(), &dscfg); err != nil { - return fmt.Errorf("datastore s3: %v", err) - } - - ds, err := openS3Datastore(dscfg) - if err != nil { - return err - } - - r.ds = ds default: return fmt.Errorf("unknown datastore type: %s", r.config.Datastore.Type) } diff --git a/test/dependencies/iptb/main.go b/test/dependencies/iptb/main.go index 3507302ad..71866ee33 100644 --- a/test/dependencies/iptb/main.go +++ b/test/dependencies/iptb/main.go @@ -1,492 +1,17 @@ package main import ( - "encoding/json" - "errors" "fmt" - "io/ioutil" - "log" + "io" "net/http" "os" - "os/exec" - "path" "strconv" "strings" - "sync" - "syscall" - "time" - kingpin "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/alecthomas/kingpin" - serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize" - - manet "gx/ipfs/QmQB7mNP3QE7b4zP2MQmsyJDqG5hzYE2CL8k1VyLWky2Ed/go-multiaddr-net" - ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr" + cli "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codegangsta/cli" + util "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util" ) -var setupOpt = func(cmd *exec.Cmd) {} - -// GetNumNodes returns the number of testbed nodes configured in the testbed directory -func GetNumNodes() int { - for i := 0; i < 2000; i++ { - _, err := os.Stat(IpfsDirN(i)) - if os.IsNotExist(err) { - return i - } - } - panic("i dont know whats going on") -} - -func TestBedDir() string { - tbd := os.Getenv("IPTB_ROOT") - if len(tbd) != 0 { - return tbd - } - - home := os.Getenv("HOME") - if len(home) == 0 { - panic("could not find home") - } - - return path.Join(home, "testbed") -} - -func IpfsDirN(n int) string { - return path.Join(TestBedDir(), fmt.Sprint(n)) -} - -func YesNoPrompt(prompt string) bool { - var s string - for { - fmt.Println(prompt) - fmt.Scanf("%s", &s) - switch s { - case "y", "Y": - return true - case "n", "N": - return false - } - fmt.Println("Please press either 'y' or 'n'") - } -} - -type initCfg struct { - Count int - Force bool - Bootstrap string - PortStart int - Mdns bool - Utp bool -} - -func (c *initCfg) swarmAddrForPeer(i int) string { - str := "/ip4/0.0.0.0/tcp/%d" - if c.Utp { - str = "/ip4/0.0.0.0/udp/%d/utp" - } - - if c.PortStart == 0 { - return fmt.Sprintf(str, 0) - } - return fmt.Sprintf(str, c.PortStart+i) -} - -func (c *initCfg) apiAddrForPeer(i int) string { - if c.PortStart == 0 { - return "/ip4/127.0.0.1/tcp/0" - } - return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.PortStart+1000+i) -} - -func IpfsInit(cfg *initCfg) error { - p := IpfsDirN(0) - if _, err := os.Stat(p); !os.IsNotExist(err) { - if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") { - return nil - } - err := os.RemoveAll(TestBedDir()) - if err != nil { - return err - } - } - wait := sync.WaitGroup{} - for i := 0; i < cfg.Count; i++ { - wait.Add(1) - go func(v int) { - defer wait.Done() - dir := IpfsDirN(v) - err := os.MkdirAll(dir, 0777) - if err != nil { - log.Println("ERROR: ", err) - return - } - - cmd := exec.Command("ipfs", "init", "-b=1024") - cmd.Env = append(cmd.Env, "IPFS_PATH="+dir) - out, err := cmd.CombinedOutput() - if err != nil { - log.Println("ERROR: ", err) - log.Println(string(out)) - } - }(i) - } - wait.Wait() - - // Now setup bootstrapping - switch cfg.Bootstrap { - case "star": - err := starBootstrap(cfg) - if err != nil { - return err - } - case "none": - err := clearBootstrapping(cfg) - if err != nil { - return err - } - default: - return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap) - } - - return nil -} - -func starBootstrap(icfg *initCfg) error { - // '0' node is the bootstrap node - cfgpath := path.Join(IpfsDirN(0), "config") - bcfg, err := serial.Load(cfgpath) - if err != nil { - return err - } - bcfg.Bootstrap = nil - bcfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(0)} - bcfg.Addresses.API = icfg.apiAddrForPeer(0) - bcfg.Addresses.Gateway = "" - bcfg.Discovery.MDNS.Enabled = icfg.Mdns - err = serial.WriteConfigFile(cfgpath, bcfg) - if err != nil { - return err - } - - for i := 1; i < icfg.Count; i++ { - cfgpath := path.Join(IpfsDirN(i), "config") - cfg, err := serial.Load(cfgpath) - if err != nil { - return err - } - - ba := fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID) - ba = strings.Replace(ba, "0.0.0.0", "127.0.0.1", -1) - cfg.Bootstrap = []string{ba} - cfg.Addresses.Gateway = "" - cfg.Discovery.MDNS.Enabled = icfg.Mdns - cfg.Addresses.Swarm = []string{ - icfg.swarmAddrForPeer(i), - } - cfg.Addresses.API = icfg.apiAddrForPeer(i) - err = serial.WriteConfigFile(cfgpath, cfg) - if err != nil { - return err - } - } - return nil -} - -func clearBootstrapping(icfg *initCfg) error { - for i := 0; i < icfg.Count; i++ { - cfgpath := path.Join(IpfsDirN(i), "config") - cfg, err := serial.Load(cfgpath) - if err != nil { - return err - } - - cfg.Bootstrap = nil - cfg.Addresses.Gateway = "" - cfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(i)} - cfg.Addresses.API = icfg.apiAddrForPeer(i) - cfg.Discovery.MDNS.Enabled = icfg.Mdns - err = serial.WriteConfigFile(cfgpath, cfg) - if err != nil { - return err - } - } - return nil -} - -func IpfsPidOf(n int) (int, error) { - dir := IpfsDirN(n) - b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid")) - if err != nil { - return -1, err - } - - return strconv.Atoi(string(b)) -} - -func KillNode(i int) error { - pid, err := IpfsPidOf(i) - if err != nil { - return fmt.Errorf("error killing daemon %d: %s", i, err) - } - - p, err := os.FindProcess(pid) - if err != nil { - return fmt.Errorf("error killing daemon %d: %s", i, err) - } - err = p.Kill() - if err != nil { - return fmt.Errorf("error killing daemon %d: %s\n", i, err) - } - - p.Wait() - - err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid")) - if err != nil { - return fmt.Errorf("error removing pid file for daemon %d: %s\n", i, err) - } - - return nil -} - -func IpfsKillAll() error { - n := GetNumNodes() - for i := 0; i < n; i++ { - err := KillNode(i) - if err != nil { - return err - } - } - return nil -} - -func envForDaemon(n int) []string { - envs := os.Environ() - npath := "IPFS_PATH=" + IpfsDirN(n) - for i, e := range envs { - p := strings.Split(e, "=") - if p[0] == "IPFS_PATH" { - envs[i] = npath - return envs - } - } - - return append(envs, npath) -} - -func IpfsStart(waitall bool) error { - var addrs []string - n := GetNumNodes() - for i := 0; i < n; i++ { - dir := IpfsDirN(i) - cmd := exec.Command("ipfs", "daemon") - cmd.Dir = dir - cmd.Env = envForDaemon(i) - - setupOpt(cmd) - - stdout, err := os.Create(path.Join(dir, "daemon.stdout")) - if err != nil { - return err - } - - stderr, err := os.Create(path.Join(dir, "daemon.stderr")) - if err != nil { - return err - } - - cmd.Stdout = stdout - cmd.Stderr = stderr - - err = cmd.Start() - if err != nil { - return err - } - pid := cmd.Process.Pid - - fmt.Printf("Started daemon %d, pid = %d\n", i, pid) - err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666) - if err != nil { - return err - } - - // Make sure node 0 is up before starting the rest so - // bootstrapping works properly - cfg, err := serial.Load(path.Join(IpfsDirN(i), "config")) - if err != nil { - return err - } - - maddr := ma.StringCast(cfg.Addresses.API) - _, addr, err := manet.DialArgs(maddr) - if err != nil { - return err - } - - addrs = append(addrs, addr) - - err = waitOnAPI(cfg.Identity.PeerID, i) - if err != nil { - return err - } - } - if waitall { - for i := 0; i < n; i++ { - err := waitOnSwarmPeers(i) - if err != nil { - return err - } - } - - } - return nil -} - -func waitOnAPI(peerid string, nnum int) error { - for i := 0; i < 50; i++ { - err := tryAPICheck(peerid, nnum) - if err == nil { - return nil - } - time.Sleep(time.Millisecond * 200) - } - return fmt.Errorf("node %d failed to come online in given time period", nnum) -} - -func getNodesAPIAddr(nnum int) (string, error) { - addrb, err := ioutil.ReadFile(path.Join(IpfsDirN(nnum), "api")) - if err != nil { - return "", err - } - - maddr, err := ma.NewMultiaddr(string(addrb)) - if err != nil { - fmt.Println("error parsing multiaddr: ", err) - return "", err - } - - _, addr, err := manet.DialArgs(maddr) - if err != nil { - fmt.Println("error on multiaddr dialargs: ", err) - return "", err - } - return addr, nil -} - -func tryAPICheck(peerid string, nnum int) error { - addr, err := getNodesAPIAddr(nnum) - if err != nil { - return err - } - - resp, err := http.Get("http://" + addr + "/api/v0/id") - if err != nil { - return err - } - - out := make(map[string]interface{}) - err = json.NewDecoder(resp.Body).Decode(&out) - if err != nil { - return fmt.Errorf("liveness check failed: %s", err) - } - - id, ok := out["ID"] - if !ok { - return fmt.Errorf("liveness check failed: ID field not present in output") - } - - idstr := id.(string) - if idstr != peerid { - return fmt.Errorf("liveness check failed: unexpected peer at endpoint") - } - - return nil -} - -func waitOnSwarmPeers(nnum int) error { - addr, err := getNodesAPIAddr(nnum) - if err != nil { - return err - } - - for i := 0; i < 50; i++ { - resp, err := http.Get("http://" + addr + "/api/v0/swarm/peers") - if err == nil { - out := make(map[string]interface{}) - err := json.NewDecoder(resp.Body).Decode(&out) - if err != nil { - return fmt.Errorf("liveness check failed: %s", err) - } - - peers := out["Strings"].([]interface{}) - if len(peers) == 0 { - time.Sleep(time.Millisecond * 200) - continue - } - - return nil - } - time.Sleep(time.Millisecond * 200) - } - return fmt.Errorf("node at %s failed to bootstrap in given time period", addr) -} - -// GetPeerID reads the config of node 'n' and returns its peer ID -func GetPeerID(n int) (string, error) { - cfg, err := serial.Load(path.Join(IpfsDirN(n), "config")) - if err != nil { - return "", err - } - return cfg.Identity.PeerID, nil -} - -// IpfsShell sets up environment variables for a new shell to more easily -// control the given daemon -func IpfsShell(n int) error { - shell := os.Getenv("SHELL") - if shell == "" { - return fmt.Errorf("couldnt find shell!") - } - - dir := IpfsDirN(n) - nenvs := []string{"IPFS_PATH=" + dir} - - nnodes := GetNumNodes() - for i := 0; i < nnodes; i++ { - peerid, err := GetPeerID(i) - if err != nil { - return err - } - nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid)) - } - nenvs = append(os.Environ(), nenvs...) - - return syscall.Exec(shell, []string{shell}, nenvs) -} - -func ConnectNodes(from, to int) error { - if from == to { - // skip connecting to self.. - return nil - } - fmt.Printf("connecting %d -> %d\n", from, to) - cmd := exec.Command("ipfs", "id", "-f", "") - cmd.Env = []string{"IPFS_PATH=" + IpfsDirN(to)} - out, err := cmd.Output() - if err != nil { - fmt.Println("ERR: ", string(out)) - return err - } - addr := strings.Split(string(out), "\n")[0] - - connectcmd := exec.Command("ipfs", "swarm", "connect", addr) - connectcmd.Env = []string{"IPFS_PATH=" + IpfsDirN(from)} - out, err = connectcmd.CombinedOutput() - if err != nil { - fmt.Println(string(out)) - return err - } - return nil -} - func parseRange(s string) ([]int, error) { if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") { ranges := strings.Split(s[1:len(s)-1], ",") @@ -536,52 +61,6 @@ func expandDashRange(s string) ([]int, error) { return out, nil } -func GetAttr(attr string, node int) (string, error) { - switch attr { - case "id": - return GetPeerID(node) - default: - return "", errors.New("unrecognized attribute") - } -} - -var helptext = `Ipfs Testbed - -Commands: - init - creates and initializes 'n' repos - - Options: - -n=[number of nodes] - -f - force overwriting of existing nodes - -bootstrap - select bootstrapping style for cluster - choices: star, none - - start - starts up all testbed nodes - - Options: - -wait - wait until daemons are fully initialized - stop - kills all testbed nodes - restart - kills, then restarts all testbed nodes - - shell [n] - execs your shell with environment variables set as follows: - IPFS_PATH - set to testbed node n's IPFS_PATH - NODE[x] - set to the peer ID of node x - - get [attribute] [node] - get an attribute of the given node - currently supports: "id" - -Env Vars: - -IPTB_ROOT: - Used to specify the directory that nodes will be created in. -` - func handleErr(s string, err error) { if err != nil { fmt.Fprintln(os.Stderr, s, err) @@ -590,80 +69,171 @@ func handleErr(s string, err error) { } func main() { - cfg := new(initCfg) - kingpin.Flag("n", "number of ipfs nodes to initialize").Short('n').IntVar(&cfg.Count) - kingpin.Flag("port", "port to start allocations from").Default("4002").Short('p').IntVar(&cfg.PortStart) - kingpin.Flag("force", "force initialization (overwrite existing configs)").Short('f').BoolVar(&cfg.Force) - kingpin.Flag("mdns", "turn on mdns for nodes").BoolVar(&cfg.Mdns) - kingpin.Flag("bootstrap", "select bootstrapping style for cluster").Default("star").StringVar(&cfg.Bootstrap) - kingpin.Flag("utp", "use utp for addresses").BoolVar(&cfg.Utp) - - wait := kingpin.Flag("wait", "wait for nodes to come fully online before exiting").Bool() - - var args []string - kingpin.Arg("args", "arguments").StringsVar(&args) - kingpin.Parse() - - if len(args) == 0 { - kingpin.Usage() - return + app := cli.NewApp() + app.Commands = []cli.Command{ + initCmd, + startCmd, + killCmd, + restartCmd, + shellCmd, + getCmd, + connectCmd, + dumpStacksCmd, } - switch args[0] { - case "init": - if cfg.Count == 0 { + err := app.Run(os.Args) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +var initCmd = cli.Command{ + Name: "init", + Usage: "create and initialize testbed nodes", + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "count, n", + Usage: "number of ipfs nodes to initialize", + }, + cli.IntFlag{ + Name: "port, p", + Usage: "port to start allocations from", + }, + cli.BoolFlag{ + Name: "force, f", + Usage: "force initialization (overwrite existing configs)", + }, + cli.BoolFlag{ + Name: "mdns", + Usage: "turn on mdns for nodes", + }, + cli.StringFlag{ + Name: "bootstrap", + Usage: "select bootstrapping style for cluster", + Value: "star", + }, + cli.BoolFlag{ + Name: "utp", + Usage: "use utp for addresses", + }, + cli.StringFlag{ + Name: "cfg", + Usage: "override default config with values from the given file", + }, + }, + Action: func(c *cli.Context) { + if c.Int("count") == 0 { fmt.Printf("please specify number of nodes: '%s init -n 10'\n", os.Args[0]) os.Exit(1) } - err := IpfsInit(cfg) + cfg := &util.InitCfg{ + Bootstrap: c.String("bootstrap"), + Force: c.Bool("f"), + Count: c.Int("count"), + Mdns: c.Bool("mdns"), + Utp: c.Bool("utp"), + PortStart: c.Int("port"), + Override: c.String("cfg"), + } + + err := util.IpfsInit(cfg) handleErr("ipfs init err: ", err) - case "start": - err := IpfsStart(*wait) + }, +} + +var startCmd = cli.Command{ + Name: "start", + Usage: "starts up all testbed nodes", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "wait", + Usage: "wait for nodes to fully come online before returning", + }, + }, + Action: func(c *cli.Context) { + err := util.IpfsStart(c.Bool("wait")) handleErr("ipfs start err: ", err) - case "stop", "kill": - if len(args) > 1 { - i, err := strconv.Atoi(args[1]) + }, +} + +var killCmd = cli.Command{ + Name: "kill", + Usage: "kill a given node (or all nodes if none specified)", + Aliases: []string{"stop"}, + Action: func(c *cli.Context) { + if c.Args().Present() { + i, err := strconv.Atoi(c.Args()[0]) if err != nil { fmt.Println("failed to parse node number: ", err) os.Exit(1) } - err = KillNode(i) + err = util.KillNode(i) if err != nil { fmt.Println("failed to kill node: ", err) } return } - err := IpfsKillAll() + err := util.IpfsKillAll() handleErr("ipfs kill err: ", err) - case "restart": - err := IpfsKillAll() + }, +} + +var restartCmd = cli.Command{ + Name: "restart", + Usage: "kill all nodes, then restart", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "wait", + Usage: "wait for nodes to come online before returning", + }, + }, + Action: func(c *cli.Context) { + err := util.IpfsKillAll() handleErr("ipfs kill err: ", err) - err = IpfsStart(*wait) + err = util.IpfsStart(c.Bool("wait")) handleErr("ipfs start err: ", err) - case "shell": - if len(args) < 2 { + }, +} + +var shellCmd = cli.Command{ + Name: "shell", + Usage: "execs your shell with certain environment variables set", + Description: `Starts a new shell and sets some environment variables for you: + +IPFS_PATH - set to testbed node 'n's IPFS_PATH +NODE[x] - set to the peer ID of node x +`, + Action: func(c *cli.Context) { + if !c.Args().Present() { fmt.Println("please specify which node you want a shell for") os.Exit(1) } - n, err := strconv.Atoi(args[1]) + n, err := strconv.Atoi(c.Args()[0]) handleErr("parse err: ", err) - err = IpfsShell(n) + err = util.IpfsShell(n) handleErr("ipfs shell err: ", err) - case "connect": - if len(args) < 3 { + }, +} + +var connectCmd = cli.Command{ + Name: "connect", + Usage: "connect two nodes together", + Action: func(c *cli.Context) { + if len(c.Args()) < 2 { fmt.Println("iptb connect [node] [node]") os.Exit(1) } - from, err := parseRange(args[1]) + from, err := parseRange(c.Args()[0]) if err != nil { fmt.Printf("failed to parse: %s\n", err) return } - to, err := parseRange(args[2]) + to, err := parseRange(c.Args()[1]) if err != nil { fmt.Printf("failed to parse: %s\n", err) return @@ -671,29 +241,53 @@ func main() { for _, f := range from { for _, t := range to { - err = ConnectNodes(f, t) + err = util.ConnectNodes(f, t) if err != nil { fmt.Printf("failed to connect: %s\n", err) return } } } + }, +} - case "get": - if len(args) < 3 { +var getCmd = cli.Command{ + Name: "get", + Usage: "get an attribute of the given node", + Action: func(c *cli.Context) { + if len(c.Args()) < 2 { fmt.Println("iptb get [attr] [node]") os.Exit(1) } - attr := args[1] - num, err := strconv.Atoi(args[2]) + attr := c.Args().First() + num, err := strconv.Atoi(c.Args()[1]) handleErr("error parsing node number: ", err) - val, err := GetAttr(attr, num) + val, err := util.GetAttr(attr, num) handleErr("error getting attribute: ", err) fmt.Println(val) - default: - kingpin.Usage() - fmt.Println(helptext) - os.Exit(1) - } + }, +} + +var dumpStacksCmd = cli.Command{ + Name: "dump-stack", + Usage: "get a stack dump from the given daemon", + Action: func(c *cli.Context) { + if len(c.Args()) < 1 { + fmt.Println("iptb dump-stack [node]") + os.Exit(1) + } + + num, err := strconv.Atoi(c.Args()[0]) + handleErr("error parsing node number: ", err) + + addr, err := util.GetNodesAPIAddr(num) + handleErr("failed to get api addr: ", err) + + resp, err := http.Get("http://" + addr + "/debug/pprof/goroutine?debug=2") + handleErr("GET stack dump failed: ", err) + defer resp.Body.Close() + + io.Copy(os.Stdout, resp.Body) + }, } diff --git a/test/sharness/t0240-republisher.sh b/test/sharness/t0240-republisher.sh index 73f7b39b1..6bb5f60e4 100755 --- a/test/sharness/t0240-republisher.sh +++ b/test/sharness/t0240-republisher.sh @@ -15,7 +15,7 @@ setup_iptb() { bound=$(expr "$num_nodes" - 1) test_expect_success "iptb init" ' - iptb init -n$num_nodes --bootstrap none --port 0 + iptb init -n $num_nodes --bootstrap none --port 0 ' for i in $(test_seq 0 "$bound") diff --git a/thirdparty/s3-datastore/datastore.go b/thirdparty/s3-datastore/datastore.go deleted file mode 100644 index 6e39bc65e..000000000 --- a/thirdparty/s3-datastore/datastore.go +++ /dev/null @@ -1,78 +0,0 @@ -package s3datastore - -import ( - "encoding/hex" - "errors" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/crowdmob/goamz/s3" - datastore "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - query "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query" -) - -var _ datastore.ThreadSafeDatastore = &S3Datastore{} - -var errTODO = errors.New("TODO") - -var ErrInvalidType = errors.New("s3 datastore: invalid type error") - -type S3Datastore struct { - Client *s3.S3 - Bucket string - ACL s3.ACL -} - -func (ds *S3Datastore) encode(key datastore.Key) string { - return hex.EncodeToString(key.Bytes()) -} - -func (ds *S3Datastore) decode(raw string) (datastore.Key, bool) { - k, err := hex.DecodeString(raw) - if err != nil { - return datastore.Key{}, false - } - return datastore.NewKey(string(k)), true -} - -func (ds *S3Datastore) Put(key datastore.Key, value interface{}) (err error) { - data, ok := value.([]byte) - if !ok { - return ErrInvalidType - } - // TODO extract s3 options - - k := ds.encode(key) - acl := ds.ACL - if acl == "" { - acl = s3.Private - } - return ds.Client.Bucket(ds.Bucket).Put(k, data, "application/protobuf", acl, s3.Options{}) -} - -func (ds *S3Datastore) Get(key datastore.Key) (value interface{}, err error) { - k := ds.encode(key) - return ds.Client.Bucket(ds.Bucket).Get(k) -} - -func (ds *S3Datastore) Has(key datastore.Key) (exists bool, err error) { - k := ds.encode(key) - return ds.Client.Bucket(ds.Bucket).Exists(k) -} - -func (ds *S3Datastore) Delete(key datastore.Key) (err error) { - k := ds.encode(key) - return ds.Client.Bucket(ds.Bucket).Del(k) -} - -func (ds *S3Datastore) Query(q query.Query) (query.Results, error) { - return nil, errors.New("TODO implement query for s3 datastore?") -} - -func (ds *S3Datastore) Close() error { - return nil -} - -func (ds *S3Datastore) Batch() (datastore.Batch, error) { - return datastore.NewBasicBatch(ds), nil -} - -func (ds *S3Datastore) IsThreadSafe() {}