diff --git a/pkg/random/peer.go b/pkg/random/peer.go new file mode 100644 index 0000000..c950221 --- /dev/null +++ b/pkg/random/peer.go @@ -0,0 +1,74 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package random + +import ( + "math/rand" + "net" + + "github.com/chihaya/chihaya" +) + +// Peer generates a random chihaya.Peer. +// +// prefix is the prefix to use for the peer ID. If len(prefix) > 20, it will be +// truncated to 20 characters. If len(prefix) < 20, it will be padded with an +// alphanumeric random string to have 20 characters. +// +// v6 indicates whether an IPv6 address should be generated. +// Regardless of the length of the generated IP address, its bytes will have +// values in [1,254]. +// +// minPort and maxPort describe the range for the randomly generated port, where +// minPort <= port < maxPort. +// minPort and maxPort will be checked and altered so that +// 1 <= minPort <= maxPort <= 65536. +// If minPort == maxPort, port will be set to minPort. +func Peer(r *rand.Rand, prefix string, v6 bool, minPort, maxPort int) chihaya.Peer { + var ( + port uint16 + ip net.IP + ) + + if minPort <= 0 { + minPort = 1 + } + if maxPort > 65536 { + maxPort = 65536 + } + if maxPort < minPort { + maxPort = minPort + } + if len(prefix) > 20 { + prefix = prefix[:20] + } + + if minPort == maxPort { + port = uint16(minPort) + } else { + port = uint16(r.Int63()%int64(maxPort-minPort)) + uint16(minPort) + } + + if v6 { + b := make([]byte, 16) + ip = net.IP(b) + } else { + b := make([]byte, 4) + ip = net.IP(b) + } + + for i := range ip { + b := r.Intn(254) + 1 + ip[i] = byte(b) + } + + prefix = prefix + AlphaNumericString(r, 20-len(prefix)) + + return chihaya.Peer{ + ID: chihaya.PeerID(prefix), + Port: port, + IP: ip, + } +} diff --git a/pkg/random/peer_test.go b/pkg/random/peer_test.go new file mode 100644 index 0000000..f3c883c --- /dev/null +++ b/pkg/random/peer_test.go @@ -0,0 +1,43 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package random + +import ( + "math/rand" + "net" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPeer(t *testing.T) { + r := rand.New(rand.NewSource(0)) + + for i := 0; i < 100; i++ { + minPort := 2000 + maxPort := 2010 + p := Peer(r, "", false, minPort, maxPort) + assert.Equal(t, 20, len(p.ID)) + assert.True(t, p.Port >= uint16(minPort) && p.Port < uint16(maxPort)) + assert.NotNil(t, p.IP.To4()) + } + + for i := 0; i < 100; i++ { + minPort := 2000 + maxPort := 2010 + p := Peer(r, "", true, minPort, maxPort) + assert.Equal(t, 20, len(p.ID)) + assert.True(t, p.Port >= uint16(minPort) && p.Port < uint16(maxPort)) + assert.True(t, len(p.IP) == net.IPv6len) + } + + p := Peer(r, "abcdefghijklmnopqrst", false, 2000, 2000) + assert.Equal(t, "abcdefghijklmnopqrst", string(p.ID)) + assert.Equal(t, uint16(2000), p.Port) + + p = Peer(r, "abcdefghijklmnopqrstUVWXYZ", true, -10, -5) + assert.Equal(t, "abcdefghijklmnopqrst", string(p.ID)) + assert.True(t, p.Port >= uint16(1) && p.Port <= uint16(65535)) +} diff --git a/pkg/random/string.go b/pkg/random/string.go new file mode 100644 index 0000000..bdfa9f2 --- /dev/null +++ b/pkg/random/string.go @@ -0,0 +1,26 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package random + +import "math/rand" + +// AlphaNumeric is an alphabet with all lower- and uppercase letters and +// numbers. +const AlphaNumeric = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +// AlphaNumericString is a shorthand for String(r, l, AlphaNumeric). +func AlphaNumericString(r rand.Source, l int) string { + return String(r, l, AlphaNumeric) +} + +// String generates a random string of length l, containing only runes from +// the alphabet using the random source r. +func String(r rand.Source, l int, alphabet string) string { + b := make([]byte, l) + for i := range b { + b[i] = alphabet[r.Int63()%int64(len(alphabet))] + } + return string(b) +} diff --git a/pkg/random/string_test.go b/pkg/random/string_test.go new file mode 100644 index 0000000..e2bd0b2 --- /dev/null +++ b/pkg/random/string_test.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package random + +import ( + "math/rand" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAlphaNumericString(t *testing.T) { + r := rand.NewSource(0) + + s := AlphaNumericString(r, 0) + assert.Equal(t, 0, len(s)) + + s = AlphaNumericString(r, 10) + assert.Equal(t, 10, len(s)) + + for i := 0; i < 100; i++ { + s := AlphaNumericString(r, 10) + for _, c := range s { + assert.True(t, strings.Contains(AlphaNumeric, string(c))) + } + } +}