mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-02 21:13:12 +00:00
commit
62d4c740c2
21
Godeps/Godeps.json
generated
21
Godeps/Godeps.json
generated
@ -1,18 +1,31 @@
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr-net",
|
||||
"GoVersion": "go1.3",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/h2so5/utp",
|
||||
"Rev": "654d875bb65e96729678180215cf080fe2810371"
|
||||
"Rev": "5288a05e1781334589c4b8806bcfb1e69f5b5d63"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-base58",
|
||||
"Rev": "568a28d73fd97651d3442392036a658b6976eed5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr",
|
||||
"Comment": "0.1.2-34-g0d7b54b",
|
||||
"Rev": "0d7b54ba432fda14bac37cdad717bd6270eacc85"
|
||||
"Comment": "0.1.2-38-gc13f11b",
|
||||
"Rev": "c13f11bbfe6439771f4df7bfb330f686826144e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multihash",
|
||||
"Comment": "0.1.0-36-g87e53a9",
|
||||
"Rev": "87e53a9d2875a18a7863b351d22f912545e6b3a3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/sha3",
|
||||
"Rev": "1351f936d976c60a0a48d728281922cf63eafb8d"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
4
Godeps/_workspace/src/github.com/h2so5/utp/.travis.yml
generated
vendored
4
Godeps/_workspace/src/github.com/h2so5/utp/.travis.yml
generated
vendored
@ -1,7 +1,9 @@
|
||||
language: go
|
||||
|
||||
script:
|
||||
- GO_UTP_LOGGING=2 go test -v -bench .
|
||||
- GO_UTP_LOGGING=2 go test -v
|
||||
- GOMAXPROCS=4 GO_UTP_LOGGING=2 go test -v
|
||||
- go test -v -race
|
||||
- GO_UTP_LOGGING=2 go run benchmark/main.go -h
|
||||
- GOMAXPROCS=4 GO_UTP_LOGGING=2 go run benchmark/main.go -h
|
||||
- GO_UTP_LOGGING=2 cd _ucat_test; make test
|
||||
|
||||
49
Godeps/_workspace/src/github.com/h2so5/utp/README.md
generated
vendored
49
Godeps/_workspace/src/github.com/h2so5/utp/README.md
generated
vendored
@ -3,55 +3,26 @@ utp
|
||||
|
||||
μTP (Micro Transport Protocol) implementation
|
||||
|
||||
[](https://ci.appveyor.com/project/h2so5/utp)
|
||||
[](https://travis-ci.org/h2so5/utp)
|
||||
[](https://ci.appveyor.com/project/h2so5/utp)
|
||||
[](https://travis-ci.org/h2so5/utp)
|
||||
[](http://godoc.org/github.com/h2so5/utp)
|
||||
|
||||
http://www.bittorrent.org/beps/bep_0029.html
|
||||
|
||||
**warning: This is a buggy alpha version.**
|
||||
|
||||
## Benchmark History
|
||||
|
||||
[]()
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get github.com/h2so5/utp
|
||||
```
|
||||
|
||||
## Example
|
||||
## Debug Log
|
||||
|
||||
Echo server
|
||||
Use GO_UTP_LOGGING to show debug logs.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/h2so5/utp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ln, _ := utp.Listen("utp", ":11000")
|
||||
defer ln.Close()
|
||||
|
||||
conn, _ := ln.AcceptUTP()
|
||||
conn.SetKeepAlive(time.Minute)
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
var buf [1024]byte
|
||||
l, err := conn.Read(buf[:])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
_, err = conn.Write(buf[:l])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
GO_UTP_LOGGING=0 go test <- default, no logging
|
||||
GO_UTP_LOGGING=1 go test
|
||||
GO_UTP_LOGGING=2 go test
|
||||
GO_UTP_LOGGING=3 go test
|
||||
GO_UTP_LOGGING=4 go test <- most verbose
|
||||
```
|
||||
|
||||
36
Godeps/_workspace/src/github.com/h2so5/utp/addr.go
generated
vendored
36
Godeps/_workspace/src/github.com/h2so5/utp/addr.go
generated
vendored
@ -2,11 +2,31 @@ package utp
|
||||
|
||||
import "net"
|
||||
|
||||
type UTPAddr struct {
|
||||
// Addr represents the address of a UTP end point.
|
||||
type Addr struct {
|
||||
net.Addr
|
||||
}
|
||||
|
||||
func (a UTPAddr) Network() string { return "utp" }
|
||||
// Network returns the address's network name, "utp".
|
||||
func (a Addr) Network() string { return "utp" }
|
||||
|
||||
// ResolveAddr parses addr as a UTP address of the form "host:port"
|
||||
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
|
||||
// port name on the network net, which must be "utp", "utp4" or
|
||||
// "utp6". A literal address or host name for IPv6 must be enclosed
|
||||
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
|
||||
// "[ipv6-host%zone]:80".
|
||||
func ResolveAddr(n, addr string) (*Addr, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udp, err := net.ResolveUDPAddr(udpnet, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Addr{Addr: udp}, nil
|
||||
}
|
||||
|
||||
func utp2udp(n string) (string, error) {
|
||||
switch n {
|
||||
@ -20,15 +40,3 @@ func utp2udp(n string) (string, error) {
|
||||
return "", net.UnknownNetworkError(n)
|
||||
}
|
||||
}
|
||||
|
||||
func ResolveUTPAddr(n, addr string) (*UTPAddr, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udp, err := net.ResolveUDPAddr(udpnet, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UTPAddr{Addr: udp}, nil
|
||||
}
|
||||
|
||||
315
Godeps/_workspace/src/github.com/h2so5/utp/base.go
generated
vendored
Normal file
315
Godeps/_workspace/src/github.com/h2so5/utp/base.go
generated
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var baseConnMap = make(map[string]*baseConn)
|
||||
var baseConnMutex sync.Mutex
|
||||
|
||||
type packetHandler chan<- *packet
|
||||
|
||||
type baseConn struct {
|
||||
addr string
|
||||
conn net.PacketConn
|
||||
synPackets *packetRingBuffer
|
||||
outOfBandPackets *packetRingBuffer
|
||||
|
||||
handlers map[uint16]packetHandler
|
||||
handlerMutex sync.RWMutex
|
||||
ref int32
|
||||
refMutex sync.RWMutex
|
||||
|
||||
rdeadline time.Time
|
||||
wdeadline time.Time
|
||||
|
||||
softClosed int32
|
||||
closed int32
|
||||
}
|
||||
|
||||
func newBaseConn(n string, addr *Addr) (*baseConn, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var s string
|
||||
if addr != nil {
|
||||
s = addr.String()
|
||||
} else {
|
||||
s = ":0"
|
||||
}
|
||||
conn, err := net.ListenPacket(udpnet, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &baseConn{
|
||||
conn: conn,
|
||||
synPackets: newPacketRingBuffer(packetBufferSize),
|
||||
outOfBandPackets: newPacketRingBuffer(packetBufferSize),
|
||||
handlers: make(map[uint16]packetHandler),
|
||||
}
|
||||
c.Register(-1, nil)
|
||||
go c.recvLoop()
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getSharedBaseConn(n string, addr *Addr) (*baseConn, error) {
|
||||
baseConnMutex.Lock()
|
||||
defer baseConnMutex.Unlock()
|
||||
var s string
|
||||
if addr != nil {
|
||||
s = addr.String()
|
||||
} else {
|
||||
s = ":0"
|
||||
}
|
||||
if c, ok := baseConnMap[s]; ok {
|
||||
return c, nil
|
||||
}
|
||||
c, err := newBaseConn(n, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.addr = s
|
||||
baseConnMap[s] = c
|
||||
go c.recvLoop()
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *baseConn) ok() bool { return c != nil && c.conn != nil }
|
||||
|
||||
func (c *baseConn) LocalAddr() net.Addr {
|
||||
if !c.ok() {
|
||||
return nil
|
||||
}
|
||||
return &Addr{Addr: c.conn.LocalAddr()}
|
||||
}
|
||||
|
||||
func (c *baseConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
if !c.ok() {
|
||||
return 0, nil, syscall.EINVAL
|
||||
}
|
||||
if !c.isOpen() {
|
||||
return 0, nil, &net.OpError{
|
||||
Op: "read",
|
||||
Net: c.LocalAddr().Network(),
|
||||
Addr: c.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
}
|
||||
var d time.Duration
|
||||
if !c.rdeadline.IsZero() {
|
||||
d = c.rdeadline.Sub(time.Now())
|
||||
if d < 0 {
|
||||
d = 0
|
||||
}
|
||||
}
|
||||
p, err := c.outOfBandPackets.popOne(d)
|
||||
if err != nil {
|
||||
return 0, nil, &net.OpError{
|
||||
Op: "read",
|
||||
Net: c.LocalAddr().Network(),
|
||||
Addr: c.LocalAddr(),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return copy(b, p.payload), p.addr, nil
|
||||
}
|
||||
|
||||
func (c *baseConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
}
|
||||
if !c.isOpen() {
|
||||
return 0, &net.OpError{
|
||||
Op: "write",
|
||||
Net: c.LocalAddr().Network(),
|
||||
Addr: c.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
}
|
||||
return c.conn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (c *baseConn) Close() error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if c.isOpen() && atomic.CompareAndSwapInt32(&c.softClosed, 0, 1) {
|
||||
c.Unregister(-1)
|
||||
} else {
|
||||
return &net.OpError{
|
||||
Op: "close",
|
||||
Net: c.LocalAddr().Network(),
|
||||
Addr: c.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *baseConn) SetDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
err := c.SetReadDeadline(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (c *baseConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.rdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *baseConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.wdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *baseConn) recvLoop() {
|
||||
var buf [maxUdpPayload]byte
|
||||
for {
|
||||
l, addr, err := c.conn.ReadFrom(buf[:])
|
||||
if err != nil {
|
||||
ulog.Printf(3, "baseConn(%v): %v", c.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
p, err := c.decodePacket(buf[:l])
|
||||
if err != nil {
|
||||
ulog.Printf(3, "baseConn(%v): RECV out-of-band packet (len: %d) from %v", c.LocalAddr(), l, addr)
|
||||
c.outOfBandPackets.push(&packet{payload: append([]byte{}, buf[:l]...), addr: addr})
|
||||
} else {
|
||||
p.addr = addr
|
||||
ulog.Printf(3, "baseConn(%v): RECV: %v from %v", c.LocalAddr(), p, addr)
|
||||
if p.header.typ == stSyn {
|
||||
// ignore duplicated syns
|
||||
if !c.exists(p.header.id + 1) {
|
||||
c.synPackets.push(p)
|
||||
}
|
||||
} else {
|
||||
c.processPacket(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) decodePacket(b []byte) (*packet, error) {
|
||||
var p packet
|
||||
err := p.UnmarshalBinary(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.header.ver != version {
|
||||
return nil, errors.New("unsupported utp version")
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (c *baseConn) exists(id uint16) bool {
|
||||
c.handlerMutex.RLock()
|
||||
defer c.handlerMutex.RUnlock()
|
||||
return c.handlers[id] != nil
|
||||
}
|
||||
|
||||
func (c *baseConn) processPacket(p *packet) {
|
||||
c.handlerMutex.RLock()
|
||||
h, ok := c.handlers[p.header.id]
|
||||
c.handlerMutex.RUnlock()
|
||||
if ok {
|
||||
h <- p
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) Register(id int32, f packetHandler) {
|
||||
if id < 0 {
|
||||
c.refMutex.Lock()
|
||||
c.ref++
|
||||
c.refMutex.Unlock()
|
||||
} else {
|
||||
if f == nil {
|
||||
panic("nil handler not allowed")
|
||||
}
|
||||
c.handlerMutex.Lock()
|
||||
_, ok := c.handlers[uint16(id)]
|
||||
c.handlerMutex.Unlock()
|
||||
if !ok {
|
||||
c.refMutex.Lock()
|
||||
c.ref++
|
||||
c.refMutex.Unlock()
|
||||
c.handlerMutex.Lock()
|
||||
c.handlers[uint16(id)] = f
|
||||
c.handlerMutex.Unlock()
|
||||
ulog.Printf(2, "baseConn(%v): register #%d (ref: %d)", c.LocalAddr(), id, c.ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) Unregister(id int32) {
|
||||
if id < 0 {
|
||||
c.refMutex.Lock()
|
||||
c.ref--
|
||||
c.refMutex.Unlock()
|
||||
} else {
|
||||
c.handlerMutex.Lock()
|
||||
_, ok := c.handlers[uint16(id)]
|
||||
c.handlerMutex.Unlock()
|
||||
if ok {
|
||||
c.handlerMutex.Lock()
|
||||
delete(c.handlers, uint16(id))
|
||||
c.handlerMutex.Unlock()
|
||||
c.refMutex.Lock()
|
||||
c.ref--
|
||||
c.refMutex.Unlock()
|
||||
}
|
||||
}
|
||||
c.refMutex.Lock()
|
||||
r := c.ref
|
||||
c.refMutex.Unlock()
|
||||
if r <= 0 {
|
||||
baseConnMutex.Lock()
|
||||
defer baseConnMutex.Unlock()
|
||||
c.close()
|
||||
delete(baseConnMap, c.addr)
|
||||
ulog.Printf(2, "baseConn(%v): unregister #%d (ref: %d)", c.LocalAddr(), id, c.ref)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) close() {
|
||||
if atomic.CompareAndSwapInt32(&c.closed, 0, 1) {
|
||||
c.conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) isOpen() bool {
|
||||
return atomic.LoadInt32(&c.closed) == 0
|
||||
}
|
||||
|
||||
func (c *baseConn) Send(p *packet) {
|
||||
b, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ulog.Printf(3, "baseConn(%v): SEND: %v to %v", c.LocalAddr(), p, p.addr)
|
||||
_, err = c.conn.WriteTo(b, p.addr)
|
||||
if err != nil {
|
||||
ulog.Printf(3, "%v", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseConn) RecvSyn(timeout time.Duration) (*packet, error) {
|
||||
return c.synPackets.popOne(timeout)
|
||||
}
|
||||
308
Godeps/_workspace/src/github.com/h2so5/utp/base_test.go
generated
vendored
Normal file
308
Godeps/_workspace/src/github.com/h2so5/utp/base_test.go
generated
vendored
Normal file
@ -0,0 +1,308 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSharedConnRecvPacket(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
ch := make(chan *packet)
|
||||
c.Register(5, ch)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
p := &packet{header: header{typ: stData, ver: version, id: 5}}
|
||||
payload, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
uc.Write(payload)
|
||||
}()
|
||||
<-ch
|
||||
}
|
||||
|
||||
c.Unregister(5)
|
||||
}
|
||||
|
||||
func TestSharedConnSendPacket(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
addr, err := net.ResolveUDPAddr("udp", uc.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := &packet{header: header{typ: stData, ver: version, id: 5}, addr: addr}
|
||||
payload, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c.Send(p)
|
||||
|
||||
var b [256]byte
|
||||
l, err := uc.Read(b[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b[:l], payload) {
|
||||
t.Errorf("expected packet of %v; got %v", payload, b[:l])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedConnRecvSyn(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
p := &packet{header: header{typ: stSyn, ver: version}}
|
||||
payload, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
uc.Write(payload)
|
||||
}()
|
||||
p, err = c.RecvSyn(time.Duration(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p == nil {
|
||||
t.Errorf("packet must not be nil")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedConnRecvOutOfBound(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
payload := []byte("Hello")
|
||||
go func() {
|
||||
uc.Write(payload)
|
||||
}()
|
||||
var b [256]byte
|
||||
l, _, err := c.ReadFrom(b[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(payload, b[:l]) {
|
||||
t.Errorf("expected packet of %v; got %v", payload, b[:l])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedConnSendOutOfBound(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
addr, err := net.ResolveUDPAddr("udp", uc.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
payload := []byte("Hello")
|
||||
_, err = c.WriteTo(payload, addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var b [256]byte
|
||||
l, err := uc.Read(b[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload, b[:l]) {
|
||||
t.Errorf("expected packet of %v; got %v", payload, b[:l])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedConnReferenceCount(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var w sync.WaitGroup
|
||||
|
||||
c.Register(-1, nil)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
w.Add(1)
|
||||
go func(i int) {
|
||||
defer w.Done()
|
||||
c.Register(int32(i), make(chan *packet))
|
||||
}(i)
|
||||
}
|
||||
|
||||
w.Wait()
|
||||
for i := 0; i < 5; i++ {
|
||||
w.Add(1)
|
||||
go func(i int) {
|
||||
defer w.Done()
|
||||
c.Unregister(int32(i))
|
||||
}(i)
|
||||
}
|
||||
|
||||
w.Wait()
|
||||
c.Unregister(-1)
|
||||
c.Close()
|
||||
|
||||
c = baseConnMap[addr.String()]
|
||||
if c != nil {
|
||||
t.Errorf("baseConn should be released", c.ref)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedConnClose(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := getSharedBaseConn("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
var b [256]byte
|
||||
_, _, err = c.ReadFrom(b[:])
|
||||
if err == nil {
|
||||
t.Fatal("ReadFrom should fail")
|
||||
}
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", c.LocalAddr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
payload := []byte("Hello")
|
||||
_, err = c.WriteTo(payload, uc.LocalAddr())
|
||||
if err == nil {
|
||||
t.Fatal("WriteTo should fail")
|
||||
}
|
||||
}
|
||||
84
Godeps/_workspace/src/github.com/h2so5/utp/benchmark/main.go
generated
vendored
84
Godeps/_workspace/src/github.com/h2so5/utp/benchmark/main.go
generated
vendored
@ -85,25 +85,27 @@ func main() {
|
||||
}
|
||||
|
||||
func c2s(l int64, stream bool) float64 {
|
||||
ln, err := utp.Listen("utp", "127.0.0.1:0")
|
||||
laddr, err := utp.ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ln, err := utp.Listen("utp", laddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cch := make(chan *utp.Conn)
|
||||
go func() {
|
||||
c, err := utp.DialUTPTimeout("utp", nil, ln.Addr().(*utp.Addr), 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := utp.DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cch <- c
|
||||
}()
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
@ -112,7 +114,11 @@ func c2s(l int64, stream bool) float64 {
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
c := <-cch
|
||||
defer c.Close()
|
||||
|
||||
rch := make(chan int)
|
||||
wch := make(chan int)
|
||||
|
||||
sendHash := md5.New()
|
||||
readHash := md5.New()
|
||||
@ -122,12 +128,13 @@ func c2s(l int64, stream bool) float64 {
|
||||
if stream {
|
||||
go func() {
|
||||
defer c.Close()
|
||||
defer close(wch)
|
||||
io.Copy(io.MultiWriter(c, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer close(rch)
|
||||
io.Copy(readHash, s)
|
||||
close(rch)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
@ -148,6 +155,7 @@ func c2s(l int64, stream bool) float64 {
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
<-wch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
} else {
|
||||
@ -156,16 +164,18 @@ func c2s(l int64, stream bool) float64 {
|
||||
|
||||
go func() {
|
||||
defer c.Close()
|
||||
defer close(wch)
|
||||
io.Copy(c, &sendBuf)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer close(rch)
|
||||
io.Copy(&readBuf, s)
|
||||
rch <- 0
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
<-wch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
io.Copy(sendHash, &sendBuf)
|
||||
@ -180,25 +190,27 @@ func c2s(l int64, stream bool) float64 {
|
||||
}
|
||||
|
||||
func s2c(l int64, stream bool) float64 {
|
||||
ln, err := utp.Listen("utp", "127.0.0.1:0")
|
||||
laddr, err := utp.ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ln, err := utp.Listen("utp", laddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cch := make(chan *utp.Conn)
|
||||
go func() {
|
||||
c, err := utp.DialUTPTimeout("utp", nil, ln.Addr().(*utp.Addr), 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := utp.DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cch <- c
|
||||
}()
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
@ -207,7 +219,11 @@ func s2c(l int64, stream bool) float64 {
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
c := <-cch
|
||||
defer c.Close()
|
||||
|
||||
rch := make(chan int)
|
||||
wch := make(chan int)
|
||||
|
||||
sendHash := md5.New()
|
||||
readHash := md5.New()
|
||||
@ -218,12 +234,13 @@ func s2c(l int64, stream bool) float64 {
|
||||
if stream {
|
||||
go func() {
|
||||
defer s.Close()
|
||||
defer close(wch)
|
||||
io.Copy(io.MultiWriter(s, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer close(rch)
|
||||
io.Copy(readHash, c)
|
||||
close(rch)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
@ -244,6 +261,7 @@ func s2c(l int64, stream bool) float64 {
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
<-wch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
} else {
|
||||
@ -252,16 +270,18 @@ func s2c(l int64, stream bool) float64 {
|
||||
|
||||
go func() {
|
||||
defer s.Close()
|
||||
defer close(wch)
|
||||
io.Copy(s, &sendBuf)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer close(rch)
|
||||
io.Copy(&readBuf, c)
|
||||
rch <- 0
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
<-wch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
io.Copy(sendHash, &sendBuf)
|
||||
|
||||
299
Godeps/_workspace/src/github.com/h2so5/utp/buffer.go
generated
vendored
299
Godeps/_workspace/src/github.com/h2so5/utp/buffer.go
generated
vendored
@ -2,7 +2,9 @@ package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -74,7 +76,7 @@ func (b *packetBuffer) compact() {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *packetBuffer) first() *packet {
|
||||
func (b *packetBuffer) front() *packet {
|
||||
if b.root == nil || b.root.p == nil {
|
||||
return nil
|
||||
}
|
||||
@ -157,6 +159,9 @@ func (b *packetBuffer) generateSelectiveACK() []byte {
|
||||
ack = ack[:len(ack)-1]
|
||||
}
|
||||
|
||||
if len(ack) == 0 {
|
||||
return nil
|
||||
}
|
||||
return ack
|
||||
}
|
||||
|
||||
@ -185,46 +190,280 @@ func (b *packetBuffer) processSelectiveACK(ack []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
type timedBuffer struct {
|
||||
d time.Duration
|
||||
root *timedBufferNode
|
||||
type packetRingBuffer struct {
|
||||
b []*packet
|
||||
begin int
|
||||
s int
|
||||
mutex sync.RWMutex
|
||||
rch chan int
|
||||
}
|
||||
|
||||
type timedBufferNode struct {
|
||||
val float64
|
||||
next *timedBufferNode
|
||||
pushed time.Time
|
||||
func newPacketRingBuffer(s int) *packetRingBuffer {
|
||||
return &packetRingBuffer{
|
||||
b: make([]*packet, s),
|
||||
rch: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *timedBuffer) push(val float64) {
|
||||
var before *timedBufferNode
|
||||
for n := b.root; n != nil; n = n.next {
|
||||
if time.Now().Sub(n.pushed) >= b.d {
|
||||
if before != nil {
|
||||
before.next = nil
|
||||
} else {
|
||||
b.root = nil
|
||||
func (b *packetRingBuffer) size() int {
|
||||
b.mutex.RLock()
|
||||
defer b.mutex.RUnlock()
|
||||
return b.s
|
||||
}
|
||||
|
||||
func (b *packetRingBuffer) empty() bool {
|
||||
return b.size() == 0
|
||||
}
|
||||
|
||||
func (b *packetRingBuffer) push(p *packet) {
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
b.b[(b.begin+b.s)%len(b.b)] = p
|
||||
if b.s < len(b.b) {
|
||||
b.s++
|
||||
} else {
|
||||
b.begin = (b.begin + 1) % len(b.b)
|
||||
}
|
||||
select {
|
||||
case b.rch <- 0:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (b *packetRingBuffer) pop() *packet {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
p := b.b[b.begin]
|
||||
b.begin = (b.begin + 1) % len(b.b)
|
||||
b.s--
|
||||
return p
|
||||
}
|
||||
|
||||
func (b *packetRingBuffer) popOne(timeout time.Duration) (*packet, error) {
|
||||
var t <-chan time.Time
|
||||
if timeout != 0 {
|
||||
t = time.After(timeout)
|
||||
}
|
||||
if b.empty() {
|
||||
select {
|
||||
case <-b.rch:
|
||||
case <-t:
|
||||
return nil, errTimeout
|
||||
}
|
||||
}
|
||||
return b.pop(), nil
|
||||
}
|
||||
|
||||
type byteRingBuffer struct {
|
||||
b []byte
|
||||
begin int
|
||||
s int
|
||||
mutex sync.RWMutex
|
||||
rch chan int
|
||||
closech chan int
|
||||
closechMutex sync.Mutex
|
||||
}
|
||||
|
||||
func newByteRingBuffer(s int) *byteRingBuffer {
|
||||
return &byteRingBuffer{
|
||||
b: make([]byte, s),
|
||||
rch: make(chan int),
|
||||
closech: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) size() int {
|
||||
r.mutex.RLock()
|
||||
defer r.mutex.RUnlock()
|
||||
return r.s
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) space() int {
|
||||
r.mutex.RLock()
|
||||
defer r.mutex.RUnlock()
|
||||
return len(r.b) - r.s
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) empty() bool {
|
||||
return r.size() == 0
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) Write(b []byte) (int, error) {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
|
||||
for len(b) > 0 {
|
||||
end := (r.begin + r.s) % len(r.b)
|
||||
n := copy(r.b[end:], b)
|
||||
b = b[n:]
|
||||
|
||||
s := r.s + n
|
||||
if s > len(r.b) {
|
||||
r.begin = (r.begin + s - len(r.b)) % len(r.b)
|
||||
r.s = len(r.b)
|
||||
} else {
|
||||
r.s += n
|
||||
}
|
||||
}
|
||||
select {
|
||||
case r.rch <- 0:
|
||||
case <-r.closech:
|
||||
return 0, io.EOF
|
||||
default:
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) ReadTimeout(b []byte, timeout time.Duration) (int, error) {
|
||||
var t <-chan time.Time
|
||||
if timeout != 0 {
|
||||
t = time.After(timeout)
|
||||
}
|
||||
if r.empty() {
|
||||
select {
|
||||
case <-r.rch:
|
||||
case <-t:
|
||||
return 0, errTimeout
|
||||
case <-r.closech:
|
||||
return 0, io.EOF
|
||||
}
|
||||
}
|
||||
l := r.size()
|
||||
if l > len(b) {
|
||||
l = len(b)
|
||||
}
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
if r.begin+l > len(r.b) {
|
||||
n := copy(b, r.b[r.begin:])
|
||||
n = copy(b[n:], r.b[:])
|
||||
r.begin = n
|
||||
} else {
|
||||
copy(b, r.b[r.begin:r.begin+l])
|
||||
r.begin = (r.begin + l) % len(r.b)
|
||||
}
|
||||
r.s -= l
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (r *byteRingBuffer) Close() error {
|
||||
r.closechMutex.Lock()
|
||||
defer r.closechMutex.Unlock()
|
||||
select {
|
||||
case <-r.closech:
|
||||
return errClosing
|
||||
default:
|
||||
close(r.closech)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type rateLimitedBuffer struct {
|
||||
wch chan<- []byte
|
||||
closech chan int
|
||||
closechMutex sync.Mutex
|
||||
size uint32
|
||||
sizech chan uint32
|
||||
sizeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func newRateLimitedBuffer(ch chan<- []byte, size uint32) *rateLimitedBuffer {
|
||||
return &rateLimitedBuffer{
|
||||
wch: ch,
|
||||
closech: make(chan int),
|
||||
size: size,
|
||||
sizech: make(chan uint32),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rateLimitedBuffer) WriteTimeout(b []byte, timeout time.Duration) (int, error) {
|
||||
var t <-chan time.Time
|
||||
if timeout != 0 {
|
||||
t = time.After(timeout)
|
||||
}
|
||||
|
||||
for wrote := uint32(0); wrote < uint32(len(b)); {
|
||||
r.sizeMutex.Lock()
|
||||
s := r.size
|
||||
r.sizeMutex.Unlock()
|
||||
if s == 0 {
|
||||
select {
|
||||
case ns := <-r.sizech:
|
||||
s = ns
|
||||
case <-r.closech:
|
||||
return 0, errClosing
|
||||
}
|
||||
break
|
||||
}
|
||||
before = n
|
||||
if s > uint32(len(b))-wrote {
|
||||
s = uint32(len(b)) - wrote
|
||||
}
|
||||
select {
|
||||
case r.wch <- append([]byte{}, b[wrote:wrote+s]...):
|
||||
wrote += s
|
||||
r.sizeMutex.Lock()
|
||||
r.size -= uint32(s)
|
||||
r.sizeMutex.Unlock()
|
||||
case <-r.closech:
|
||||
return 0, errClosing
|
||||
case <-t:
|
||||
return 0, errTimeout
|
||||
}
|
||||
}
|
||||
b.root = &timedBufferNode{
|
||||
val: val,
|
||||
next: b.root,
|
||||
pushed: time.Now(),
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (r *rateLimitedBuffer) Reset(size uint32) {
|
||||
r.sizeMutex.Lock()
|
||||
defer r.sizeMutex.Unlock()
|
||||
r.size = size
|
||||
select {
|
||||
case r.sizech <- size:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (b *timedBuffer) min() float64 {
|
||||
if b.root == nil {
|
||||
return 0
|
||||
func (r *rateLimitedBuffer) Close() error {
|
||||
r.closechMutex.Lock()
|
||||
defer r.closechMutex.Unlock()
|
||||
select {
|
||||
case <-r.closech:
|
||||
return errClosing
|
||||
default:
|
||||
close(r.closech)
|
||||
}
|
||||
min := b.root.val
|
||||
for n := b.root; n != nil; n = n.next {
|
||||
if min > n.val {
|
||||
min = n.val
|
||||
return nil
|
||||
}
|
||||
|
||||
type baseDelayBuffer struct {
|
||||
b [6]uint32
|
||||
last int
|
||||
min uint32
|
||||
}
|
||||
|
||||
func (b *baseDelayBuffer) Push(val uint32) {
|
||||
t := time.Now()
|
||||
i := t.Second()/20 + (t.Minute()%2)*3
|
||||
if b.last == i {
|
||||
if b.b[i] > val {
|
||||
b.b[i] = val
|
||||
}
|
||||
} else {
|
||||
b.b[i] = val
|
||||
b.last = i
|
||||
}
|
||||
min := val
|
||||
for _, v := range b.b {
|
||||
if v > 0 && min > v {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
return min
|
||||
b.min = min
|
||||
}
|
||||
|
||||
func (b *baseDelayBuffer) Min() uint32 {
|
||||
return b.min
|
||||
}
|
||||
|
||||
177
Godeps/_workspace/src/github.com/h2so5/utp/buffer_test.go
generated
vendored
Normal file
177
Godeps/_workspace/src/github.com/h2so5/utp/buffer_test.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPacketBuffer(t *testing.T) {
|
||||
size := 12
|
||||
b := newPacketBuffer(12, 1)
|
||||
|
||||
if b.space() != size {
|
||||
t.Errorf("expected space == %d; got %d", size, b.space())
|
||||
}
|
||||
|
||||
for i := 1; i <= size; i++ {
|
||||
b.push(&packet{header: header{seq: uint16(i)}})
|
||||
}
|
||||
|
||||
if b.space() != 0 {
|
||||
t.Errorf("expected space == 0; got %d", b.space())
|
||||
}
|
||||
|
||||
a := []byte{255, 7}
|
||||
ack := b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
err := b.push(&packet{header: header{seq: 15}})
|
||||
if err == nil {
|
||||
t.Fatal("push should fail")
|
||||
}
|
||||
|
||||
all := b.all()
|
||||
if len(all) != size {
|
||||
t.Errorf("expected %d packets sequence; got %d", size, len(all))
|
||||
}
|
||||
|
||||
f := b.fetch(6)
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
|
||||
b.compact()
|
||||
|
||||
err = b.push(&packet{header: header{seq: 15}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = b.push(&packet{header: header{seq: 17}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 7; i <= size; i++ {
|
||||
f := b.fetch(uint16(i))
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
}
|
||||
|
||||
a = []byte{128, 2}
|
||||
ack = b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 2 {
|
||||
t.Errorf("expected 2 packets sequence; got %d", len(all))
|
||||
}
|
||||
|
||||
b.compact()
|
||||
if b.space() != 9 {
|
||||
t.Errorf("expected space == 9; got %d", b.space())
|
||||
}
|
||||
|
||||
ack = b.generateSelectiveACK()
|
||||
b.processSelectiveACK(ack)
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 1 {
|
||||
t.Errorf("expected size == 1; got %d", len(all))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketBufferBoundary(t *testing.T) {
|
||||
begin := math.MaxUint16 - 3
|
||||
b := newPacketBuffer(12, begin)
|
||||
for i := begin; i != 5; i = (i + 1) % (math.MaxUint16 + 1) {
|
||||
err := b.push(&packet{header: header{seq: uint16(i)}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketRingBuffer(t *testing.T) {
|
||||
b := newPacketRingBuffer(5)
|
||||
for i := 0; i < 7; i++ {
|
||||
b.push(&packet{header: header{seq: uint16(i)}})
|
||||
}
|
||||
|
||||
if b.size() != 5 {
|
||||
t.Errorf("expected size == 5; got %d", b.size())
|
||||
}
|
||||
|
||||
p := b.pop()
|
||||
if p.header.seq != 2 {
|
||||
t.Errorf("expected header.seq == 2; got %d", p.header.seq)
|
||||
}
|
||||
|
||||
if b.size() != 4 {
|
||||
t.Errorf("expected size == 4; got %d", b.size())
|
||||
}
|
||||
|
||||
for b.pop() != nil {}
|
||||
|
||||
if !b.empty() {
|
||||
t.Errorf("buffer must be empty")
|
||||
}
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 5; i++ {
|
||||
b.push(&packet{header: header{seq: uint16(i)}})
|
||||
}
|
||||
}()
|
||||
|
||||
p, err := b.popOne(time.Second)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if p.header.seq != 0 {
|
||||
t.Errorf("expected header.seq == 0; got %d", p.header.seq)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteRingBuffer(t *testing.T) {
|
||||
|
||||
b := newByteRingBuffer(5)
|
||||
for i := 0; i < 100; i++ {
|
||||
b.Write([]byte{byte(i)})
|
||||
}
|
||||
|
||||
var buf [10]byte
|
||||
l, err := b.ReadTimeout(buf[:], 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e := []byte{95, 96, 97, 98, 99}
|
||||
if !bytes.Equal(buf[:l], e) {
|
||||
t.Errorf("expected payload of %v; got %v", e, buf[:l])
|
||||
}
|
||||
|
||||
e2 := []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
go func() {
|
||||
_, err := b.Write(e2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
l, err = b.ReadTimeout(buf[:], 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf[:l], e2[len(e2)-5:]) {
|
||||
t.Errorf("expected payload of %v; got %v", e2[len(e2)-5:], buf[:l])
|
||||
}
|
||||
}
|
||||
850
Godeps/_workspace/src/github.com/h2so5/utp/conn.go
generated
vendored
850
Godeps/_workspace/src/github.com/h2so5/utp/conn.go
generated
vendored
File diff suppressed because it is too large
Load Diff
87
Godeps/_workspace/src/github.com/h2so5/utp/conn_test.go
generated
vendored
Normal file
87
Godeps/_workspace/src/github.com/h2so5/utp/conn_test.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadWrite(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
payload := []byte("abcdefgh")
|
||||
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var buf [256]byte
|
||||
length, err := c.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(payload, buf[:length]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload, buf[:length])
|
||||
}
|
||||
|
||||
ch <- 0
|
||||
}()
|
||||
|
||||
c, err := DialUTP("utp", nil, l.Addr().(*Addr))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
_, err = c.Write(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
go func() {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
|
||||
c, err := DialUTP("utp", nil, l.Addr().(*Addr))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var b [128]byte
|
||||
_, err = c.Read(b[:])
|
||||
if err == nil {
|
||||
t.Fatal("Read should fail")
|
||||
}
|
||||
}
|
||||
61
Godeps/_workspace/src/github.com/h2so5/utp/dial.go
generated
vendored
61
Godeps/_workspace/src/github.com/h2so5/utp/dial.go
generated
vendored
@ -2,24 +2,57 @@ package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Dial(n, addr string) (*UTPConn, error) {
|
||||
raddr, err := ResolveUTPAddr(n, addr)
|
||||
// DialUTP connects to the remote address raddr on the network net,
|
||||
// which must be "utp", "utp4", or "utp6". If laddr is not nil, it is
|
||||
// used as the local address for the connection.
|
||||
func DialUTP(n string, laddr, raddr *Addr) (*Conn, error) {
|
||||
return DialUTPTimeout(n, laddr, raddr, 0)
|
||||
}
|
||||
|
||||
// DialUTPTimeout acts like Dial but takes a timeout.
|
||||
// The timeout includes name resolution, if required.
|
||||
func DialUTPTimeout(n string, laddr, raddr *Addr, timeout time.Duration) (*Conn, error) {
|
||||
conn, err := getSharedBaseConn(n, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DialUTP(n, nil, raddr)
|
||||
}
|
||||
|
||||
func DialUTP(n string, laddr, raddr *UTPAddr) (*UTPConn, error) {
|
||||
return dial(n, laddr, raddr, 0)
|
||||
}
|
||||
id := uint16(rand.Intn(math.MaxUint16))
|
||||
c := newConn()
|
||||
c.conn = conn
|
||||
c.raddr = raddr.Addr
|
||||
c.rid = id
|
||||
c.sid = id + 1
|
||||
c.seq = 1
|
||||
c.state = stateSynSent
|
||||
c.sendbuf = newPacketBuffer(windowSize*2, 1)
|
||||
c.conn.Register(int32(c.rid), c.recv)
|
||||
go c.loop()
|
||||
c.synch <- 0
|
||||
|
||||
func DialUTPTimeout(n string, laddr, raddr *UTPAddr, timeout time.Duration) (*UTPConn, error) {
|
||||
return dial(n, laddr, raddr, timeout)
|
||||
var t <-chan time.Time
|
||||
if timeout != 0 {
|
||||
t = time.After(timeout)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.connch:
|
||||
case <-t:
|
||||
c.Close()
|
||||
return nil, &net.OpError{
|
||||
Op: "dial",
|
||||
Net: c.LocalAddr().Network(),
|
||||
Addr: c.LocalAddr(),
|
||||
Err: errTimeout,
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// A Dialer contains options for connecting to an address.
|
||||
@ -49,18 +82,18 @@ type Dialer struct {
|
||||
// Dial connects to the address on the named network.
|
||||
//
|
||||
// See func Dial for a description of the network and address parameters.
|
||||
func (d *Dialer) Dial(n, addr string) (*UTPConn, error) {
|
||||
raddr, err := ResolveUTPAddr(n, addr)
|
||||
func (d *Dialer) Dial(n, addr string) (*Conn, error) {
|
||||
raddr, err := ResolveAddr(n, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var laddr *UTPAddr
|
||||
var laddr *Addr
|
||||
if d.LocalAddr != nil {
|
||||
var ok bool
|
||||
laddr, ok = d.LocalAddr.(*UTPAddr)
|
||||
laddr, ok = d.LocalAddr.(*Addr)
|
||||
if !ok {
|
||||
return nil, errors.New("Dialer.LocalAddr is not a UTPAddr")
|
||||
return nil, errors.New("Dialer.LocalAddr is not a Addr")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
52
Godeps/_workspace/src/github.com/h2so5/utp/dial_test.go
generated
vendored
Normal file
52
Godeps/_workspace/src/github.com/h2so5/utp/dial_test.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
l.Accept()
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
c, err := DialUTP("utp", nil, l.Addr().(*Addr))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestDialFastTimeout(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
_, err = (&Dialer{
|
||||
Timeout: time.Nanosecond,
|
||||
}).Dial("utp", l.Addr().String())
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
}
|
||||
377
Godeps/_workspace/src/github.com/h2so5/utp/listener.go
generated
vendored
377
Godeps/_workspace/src/github.com/h2so5/utp/listener.go
generated
vendored
@ -1,329 +1,146 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UTPListener struct {
|
||||
// Listener is a UTP network listener. Clients should typically
|
||||
// use variables of type Listener instead of assuming UTP.
|
||||
type Listener struct {
|
||||
// RawConn represents an out-of-band connection.
|
||||
// This allows a single socket to handle multiple protocols.
|
||||
RawConn net.PacketConn
|
||||
|
||||
conn net.PacketConn
|
||||
conns map[uint16]*UTPConn
|
||||
accept chan (*UTPConn)
|
||||
err chan (error)
|
||||
lasterr error
|
||||
deadline time.Time
|
||||
closech chan int
|
||||
connch chan uint16
|
||||
closed bool
|
||||
conn *baseConn
|
||||
deadline time.Time
|
||||
deadlineMutex sync.RWMutex
|
||||
closed int32
|
||||
}
|
||||
|
||||
func Listen(n, laddr string) (*UTPListener, error) {
|
||||
addr, err := ResolveUTPAddr(n, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ListenUTP(n, addr)
|
||||
}
|
||||
func (l *Listener) ok() bool { return l != nil && l.conn != nil }
|
||||
|
||||
func ListenUTP(n string, laddr *UTPAddr) (*UTPListener, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
// Listen announces on the UTP address laddr and returns a UTP
|
||||
// listener. Net must be "utp", "utp4", or "utp6". If laddr has a
|
||||
// port of 0, ListenUTP will choose an available port. The caller can
|
||||
// use the Addr method of Listener to retrieve the chosen address.
|
||||
func Listen(n string, laddr *Addr) (*Listener, error) {
|
||||
conn, err := newBaseConn(n, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := listenPacket(udpnet, laddr.Addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := UTPListener{
|
||||
RawConn: newRawConn(conn),
|
||||
l := &Listener{
|
||||
RawConn: conn,
|
||||
conn: conn,
|
||||
conns: make(map[uint16]*UTPConn),
|
||||
accept: make(chan (*UTPConn), 10),
|
||||
err: make(chan (error), 1),
|
||||
closech: make(chan int),
|
||||
connch: make(chan uint16),
|
||||
lasterr: nil,
|
||||
}
|
||||
|
||||
l.listen()
|
||||
return &l, nil
|
||||
conn.Register(-1, nil)
|
||||
return l, nil
|
||||
}
|
||||
|
||||
type incoming struct {
|
||||
p *packet
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
func (l *UTPListener) listen() {
|
||||
inch := make(chan incoming)
|
||||
raw := l.RawConn.(*rawConn)
|
||||
|
||||
// reads udp packets
|
||||
go func() {
|
||||
for {
|
||||
var buf [mtu]byte
|
||||
len, addr, err := l.conn.ReadFrom(buf[:])
|
||||
if err != nil {
|
||||
l.err <- err
|
||||
return
|
||||
}
|
||||
p, err := readPacket(buf[:len])
|
||||
if err == nil {
|
||||
inch <- incoming{p, addr}
|
||||
} else {
|
||||
select {
|
||||
case <-raw.closed:
|
||||
default:
|
||||
i := rawIncoming{b: buf[:len], addr: addr}
|
||||
select {
|
||||
case raw.in <- i:
|
||||
default:
|
||||
// discard the oldest packet
|
||||
<-raw.in
|
||||
raw.in <- i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case i := <-inch:
|
||||
l.processPacket(i.p, i.addr)
|
||||
case <-l.closech:
|
||||
ulog.Printf(2, "Listener(%v): Stop listening", l.conn.LocalAddr())
|
||||
close(l.accept)
|
||||
l.closed = true
|
||||
case id := <-l.connch:
|
||||
if _, ok := l.conns[id]; !ok {
|
||||
delete(l.conns, id+1)
|
||||
ulog.Printf(2, "Listener(%v): Connection closed #%d (alive: %d)", l.conn.LocalAddr(), id, len(l.conns))
|
||||
if l.closed && len(l.conns) == 0 {
|
||||
ulog.Printf(2, "Listener(%v): All accepted connections are closed", l.conn.LocalAddr())
|
||||
l.conn.Close()
|
||||
ulog.Printf(1, "Listener(%v): Closed", l.conn.LocalAddr())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ulog.Printf(1, "Listener(%v): Start listening", l.conn.LocalAddr())
|
||||
}
|
||||
|
||||
func listenPacket(n, addr string) (net.PacketConn, error) {
|
||||
if n == "mem" {
|
||||
return nil, errors.New("TODO implement in-memory packet connection")
|
||||
}
|
||||
return net.ListenPacket(n, addr)
|
||||
}
|
||||
|
||||
func (l *UTPListener) processPacket(p *packet, addr net.Addr) {
|
||||
switch p.header.typ {
|
||||
case st_data, st_fin, st_state, st_reset:
|
||||
if c, ok := l.conns[p.header.id]; ok {
|
||||
select {
|
||||
case c.recvch <- p:
|
||||
case <-c.recvchch:
|
||||
}
|
||||
}
|
||||
case st_syn:
|
||||
if l.closed {
|
||||
return
|
||||
}
|
||||
sid := p.header.id + 1
|
||||
if _, ok := l.conns[p.header.id]; !ok {
|
||||
seq := rand.Intn(math.MaxUint16)
|
||||
|
||||
c := newUTPConn()
|
||||
c.conn = l.conn
|
||||
c.raddr = addr
|
||||
c.rid = p.header.id + 1
|
||||
c.sid = p.header.id
|
||||
c.seq = uint16(seq)
|
||||
c.ack = p.header.seq
|
||||
c.diff = currentMicrosecond() - p.header.t
|
||||
c.state = state_connected
|
||||
c.closech = l.connch
|
||||
c.recvbuf = newPacketBuffer(window_size, int(p.header.seq))
|
||||
c.sendbuf = newPacketBuffer(window_size, seq)
|
||||
|
||||
go c.loop()
|
||||
select {
|
||||
case c.recvch <- p:
|
||||
case <-c.recvchch:
|
||||
}
|
||||
|
||||
l.conns[sid] = c
|
||||
ulog.Printf(2, "Listener(%v): New incoming connection #%d from %v (alive: %d)", l.conn.LocalAddr(), sid, addr, len(l.conns))
|
||||
|
||||
l.accept <- c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UTPListener) Accept() (net.Conn, error) {
|
||||
// Accept implements the Accept method in the Listener interface; it
|
||||
// waits for the next call and returns a generic Conn.
|
||||
func (l *Listener) Accept() (net.Conn, error) {
|
||||
return l.AcceptUTP()
|
||||
}
|
||||
|
||||
func (l *UTPListener) AcceptUTP() (*UTPConn, error) {
|
||||
if l == nil || l.conn == nil {
|
||||
// AcceptUTP accepts the next incoming call and returns the new
|
||||
// connection.
|
||||
func (l *Listener) AcceptUTP() (*Conn, error) {
|
||||
if !l.ok() {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
if l.lasterr != nil {
|
||||
return nil, l.lasterr
|
||||
}
|
||||
var timeout <-chan time.Time
|
||||
if !l.deadline.IsZero() {
|
||||
timeout = time.After(l.deadline.Sub(time.Now()))
|
||||
}
|
||||
select {
|
||||
case conn := <-l.accept:
|
||||
if conn == nil {
|
||||
return nil, errors.New("use of closed network connection")
|
||||
if !l.isOpen() {
|
||||
return nil, &net.OpError{
|
||||
Op: "accept",
|
||||
Net: l.conn.LocalAddr().Network(),
|
||||
Addr: l.conn.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
return conn, nil
|
||||
case err := <-l.err:
|
||||
l.lasterr = err
|
||||
return nil, err
|
||||
case <-timeout:
|
||||
return nil, &timeoutError{}
|
||||
}
|
||||
l.deadlineMutex.RLock()
|
||||
d := timeToDeadline(l.deadline)
|
||||
l.deadlineMutex.RUnlock()
|
||||
p, err := l.conn.RecvSyn(d)
|
||||
if err != nil {
|
||||
return nil, &net.OpError{
|
||||
Op: "accept",
|
||||
Net: l.conn.LocalAddr().Network(),
|
||||
Addr: l.conn.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
}
|
||||
|
||||
seq := rand.Intn(math.MaxUint16)
|
||||
rid := p.header.id + 1
|
||||
|
||||
c := newConn()
|
||||
c.state = stateConnected
|
||||
c.conn = l.conn
|
||||
c.raddr = p.addr
|
||||
c.rid = p.header.id + 1
|
||||
c.sid = p.header.id
|
||||
c.seq = uint16(seq)
|
||||
c.ack = p.header.seq
|
||||
c.recvbuf = newPacketBuffer(windowSize, int(p.header.seq))
|
||||
c.sendbuf = newPacketBuffer(windowSize*2, seq)
|
||||
l.conn.Register(int32(rid), c.recv)
|
||||
go c.loop()
|
||||
c.recv <- p
|
||||
|
||||
ulog.Printf(2, "baseConn(%v): accept #%d from %v", c.LocalAddr(), c.rid, c.raddr)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (l *UTPListener) Addr() net.Addr {
|
||||
return &UTPAddr{Addr: l.conn.LocalAddr()}
|
||||
// Addr returns the listener's network address, a *Addr.
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
if !l.ok() {
|
||||
return nil
|
||||
}
|
||||
return l.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (l *UTPListener) Close() error {
|
||||
if l == nil || l.conn == nil {
|
||||
// Close stops listening on the UTP address.
|
||||
// Already Accepted connections are not closed.
|
||||
func (l *Listener) Close() error {
|
||||
if !l.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
l.closech <- 0
|
||||
l.RawConn.Close()
|
||||
if !l.close() {
|
||||
return &net.OpError{
|
||||
Op: "close",
|
||||
Net: l.conn.LocalAddr().Network(),
|
||||
Addr: l.conn.LocalAddr(),
|
||||
Err: errClosing,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *UTPListener) SetDeadline(t time.Time) error {
|
||||
if l == nil || l.conn == nil {
|
||||
// SetDeadline sets the deadline associated with the listener.
|
||||
// A zero time value disables the deadline.
|
||||
func (l *Listener) SetDeadline(t time.Time) error {
|
||||
if !l.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
l.deadlineMutex.Lock()
|
||||
defer l.deadlineMutex.Unlock()
|
||||
l.deadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
type rawIncoming struct {
|
||||
b []byte
|
||||
addr net.Addr
|
||||
func (l *Listener) close() bool {
|
||||
if atomic.CompareAndSwapInt32(&l.closed, 0, 1) {
|
||||
l.conn.Unregister(-1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type rawConn struct {
|
||||
conn net.PacketConn
|
||||
rdeadline, wdeadline time.Time
|
||||
in chan rawIncoming
|
||||
closed chan int
|
||||
}
|
||||
|
||||
func newRawConn(conn net.PacketConn) *rawConn {
|
||||
return &rawConn{
|
||||
conn: conn,
|
||||
in: make(chan rawIncoming, 100),
|
||||
closed: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawConn) ok() bool { return c != nil && c.conn != nil }
|
||||
|
||||
func (c *rawConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
if !c.ok() {
|
||||
return 0, nil, syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, nil, errors.New("use of closed network connection")
|
||||
default:
|
||||
}
|
||||
var timeout <-chan time.Time
|
||||
if !c.rdeadline.IsZero() {
|
||||
timeout = time.After(c.rdeadline.Sub(time.Now()))
|
||||
}
|
||||
select {
|
||||
case r := <-c.in:
|
||||
return copy(b, r.b), r.addr, nil
|
||||
case <-timeout:
|
||||
return 0, nil, &timeoutError{}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, errors.New("use of closed network connection")
|
||||
default:
|
||||
}
|
||||
return c.conn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (c *rawConn) Close() error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return errors.New("use of closed network connection")
|
||||
default:
|
||||
close(c.closed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) LocalAddr() net.Addr {
|
||||
if !c.ok() {
|
||||
return nil
|
||||
}
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *rawConn) SetDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if err := c.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.rdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.wdeadline = t
|
||||
return nil
|
||||
func (l *Listener) isOpen() bool {
|
||||
return atomic.LoadInt32(&l.closed) == 0
|
||||
}
|
||||
|
||||
68
Godeps/_workspace/src/github.com/h2so5/utp/listener_test.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/h2so5/utp/listener_test.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListenerAccept(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
uaddr, err := net.ResolveUDPAddr("udp", l.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
uc, err := net.DialUDP("udp", nil, uaddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
p := &packet{header: header{typ: stSyn, ver: version, id: uint16(i)}}
|
||||
payload, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
uc.Write(payload)
|
||||
}()
|
||||
|
||||
a, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListenerClose(t *testing.T) {
|
||||
addr, err := ResolveAddr("utp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := Listen("utp", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
l.Close()
|
||||
}
|
||||
|
||||
_, err = l.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should fail")
|
||||
}
|
||||
}
|
||||
74
Godeps/_workspace/src/github.com/h2so5/utp/packet.go
generated
vendored
74
Godeps/_workspace/src/github.com/h2so5/utp/packet.go
generated
vendored
@ -5,7 +5,8 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
@ -24,16 +25,11 @@ type packet struct {
|
||||
header header
|
||||
ext []extension
|
||||
payload []byte
|
||||
}
|
||||
|
||||
type outgoingPacket struct {
|
||||
typ int
|
||||
ext []extension
|
||||
payload []byte
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
func (p *packet) MarshalBinary() ([]byte, error) {
|
||||
firstExt := ext_none
|
||||
firstExt := extNone
|
||||
if len(p.ext) > 0 {
|
||||
firstExt = p.ext[0].typ
|
||||
}
|
||||
@ -68,7 +64,7 @@ func (p *packet) MarshalBinary() ([]byte, error) {
|
||||
|
||||
if len(p.ext) > 0 {
|
||||
for i, e := range p.ext {
|
||||
next := ext_none
|
||||
next := extNone
|
||||
if i < len(p.ext)-1 {
|
||||
next = p.ext[i+1].typ
|
||||
}
|
||||
@ -123,7 +119,7 @@ func (p *packet) UnmarshalBinary(data []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
for e != ext_none {
|
||||
for e != extNone {
|
||||
currentExt := int(e)
|
||||
var l uint8
|
||||
var ext = []interface{}{
|
||||
@ -173,68 +169,30 @@ func (p *packet) UnmarshalBinary(data []byte) error {
|
||||
p.header.typ = int((tv >> 4) & 0xF)
|
||||
p.header.ver = int(tv & 0xF)
|
||||
|
||||
l := buf.Len()
|
||||
if l > 0 {
|
||||
p.payload = p.payload[:l]
|
||||
_, err := buf.Read(p.payload[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := ioutil.ReadAll(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.payload = data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p packet) String() string {
|
||||
var s string = fmt.Sprintf("[%d ", p.header.id)
|
||||
s := fmt.Sprintf("[%d ", p.header.id)
|
||||
switch p.header.typ {
|
||||
case st_data:
|
||||
case stData:
|
||||
s += "ST_DATA"
|
||||
case st_fin:
|
||||
case stFin:
|
||||
s += "ST_FIN"
|
||||
case st_state:
|
||||
case stState:
|
||||
s += "ST_STATE"
|
||||
case st_reset:
|
||||
case stReset:
|
||||
s += "ST_RESET"
|
||||
case st_syn:
|
||||
case stSyn:
|
||||
s += "ST_SYN"
|
||||
}
|
||||
s += fmt.Sprintf(" seq:%d ack:%d len:%d", p.header.seq, p.header.ack, len(p.payload))
|
||||
s += "]"
|
||||
return s
|
||||
}
|
||||
|
||||
var globalPool packetPool
|
||||
|
||||
type packetPool struct {
|
||||
root *packetPoolNode
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type packetPoolNode struct {
|
||||
p *packet
|
||||
next *packetPoolNode
|
||||
}
|
||||
|
||||
func (o *packetPool) get() *packet {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
r := o.root
|
||||
if r != nil {
|
||||
o.root = o.root.next
|
||||
return r.p
|
||||
} else {
|
||||
return &packet{
|
||||
payload: make([]byte, 0, mss),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *packetPool) put(p *packet) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
o.root = &packetPoolNode{
|
||||
p: p,
|
||||
next: o.root,
|
||||
}
|
||||
}
|
||||
|
||||
64
Godeps/_workspace/src/github.com/h2so5/utp/packet_test.go
generated
vendored
Normal file
64
Godeps/_workspace/src/github.com/h2so5/utp/packet_test.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPacketBinary(t *testing.T) {
|
||||
h := header{
|
||||
typ: stFin,
|
||||
ver: version,
|
||||
id: 100,
|
||||
t: 50000,
|
||||
diff: 10000,
|
||||
wnd: 65535,
|
||||
seq: 100,
|
||||
ack: 200,
|
||||
}
|
||||
|
||||
e := []extension{
|
||||
extension{
|
||||
typ: extSelectiveAck,
|
||||
payload: []byte{0, 1, 0, 1},
|
||||
},
|
||||
extension{
|
||||
typ: extSelectiveAck,
|
||||
payload: []byte{100, 0, 200, 0},
|
||||
},
|
||||
}
|
||||
|
||||
p := packet{
|
||||
header: h,
|
||||
ext: e,
|
||||
payload: []byte("abcdefg"),
|
||||
}
|
||||
|
||||
b, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p2 := packet{payload: make([]byte, 0, mss)}
|
||||
err = p2.UnmarshalBinary(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(p, p2) {
|
||||
t.Errorf("expected packet of %v; got %v", p, p2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalShortPacket(t *testing.T) {
|
||||
b := make([]byte, 18)
|
||||
p := packet{}
|
||||
err := p.UnmarshalBinary(b)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("UnmarshalBinary should fail")
|
||||
} else if err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
8
Godeps/_workspace/src/github.com/h2so5/utp/ucat/ucat.go
generated
vendored
8
Godeps/_workspace/src/github.com/h2so5/utp/ucat/ucat.go
generated
vendored
@ -111,7 +111,11 @@ func log(format string, vals ...interface{}) {
|
||||
// Listen listens and accepts one incoming uTP connection on a given port,
|
||||
// and pipes all incoming data to os.Stdout.
|
||||
func Listen(localAddr string) error {
|
||||
l, err := utp.Listen("utp", localAddr)
|
||||
laddr, err := utp.ResolveAddr("utp", localAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve address %s", localAddr)
|
||||
}
|
||||
l, err := utp.Listen("utp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -138,7 +142,7 @@ func Dial(localAddr, remoteAddr string) error {
|
||||
var laddr net.Addr
|
||||
var err error
|
||||
if localAddr != "" {
|
||||
laddr, err = utp.ResolveUTPAddr("utp", localAddr)
|
||||
laddr, err = utp.ResolveAddr("utp", localAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve address %s", localAddr)
|
||||
}
|
||||
|
||||
44
Godeps/_workspace/src/github.com/h2so5/utp/utp.go
generated
vendored
44
Godeps/_workspace/src/github.com/h2so5/utp/utp.go
generated
vendored
@ -1,25 +1,38 @@
|
||||
package utp
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
version = 1
|
||||
|
||||
st_data = 0
|
||||
st_fin = 1
|
||||
st_state = 2
|
||||
st_reset = 3
|
||||
st_syn = 4
|
||||
stData = 0
|
||||
stFin = 1
|
||||
stState = 2
|
||||
stReset = 3
|
||||
stSyn = 4
|
||||
|
||||
ext_none = 0
|
||||
ext_selective_ack = 1
|
||||
stateClosed = iota
|
||||
stateClosing
|
||||
stateSynSent
|
||||
stateConnected
|
||||
stateFinSent
|
||||
|
||||
header_size = 20
|
||||
mtu = 3200
|
||||
mss = mtu - header_size
|
||||
window_size = 100
|
||||
extNone = 0
|
||||
extSelectiveAck = 1
|
||||
|
||||
reset_timeout = time.Second
|
||||
headerSize = 20
|
||||
mtu = 3200
|
||||
mss = mtu - headerSize
|
||||
windowSize = 100
|
||||
packetBufferSize = 256
|
||||
readBufferSize = 1048576
|
||||
maxRetry = 3
|
||||
|
||||
maxUdpPayload = 65507
|
||||
resetTimeout = time.Second
|
||||
)
|
||||
|
||||
type timeoutError struct{}
|
||||
@ -27,3 +40,8 @@ type timeoutError struct{}
|
||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||
func (e *timeoutError) Timeout() bool { return true }
|
||||
func (e *timeoutError) Temporary() bool { return true }
|
||||
|
||||
var (
|
||||
errTimeout error = &timeoutError{}
|
||||
errClosing = errors.New("use of closed network connection")
|
||||
)
|
||||
|
||||
601
Godeps/_workspace/src/github.com/h2so5/utp/utp_test.go
generated
vendored
601
Godeps/_workspace/src/github.com/h2so5/utp/utp_test.go
generated
vendored
@ -1,601 +0,0 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func TestReadWrite(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ln.Close()
|
||||
|
||||
payload := []byte("Hello!")
|
||||
_, err = c.Write(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = s.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf [256]byte
|
||||
l, err := s.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload, buf[:l]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload, buf[:l])
|
||||
}
|
||||
|
||||
payload2 := []byte("World!")
|
||||
_, err = s.Write(payload2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = c.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err = c.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload2, buf[:l]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload2, buf[:l])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawReadWrite(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
raddr, err := net.ResolveUDPAddr("udp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := net.DialUDP("udp", nil, raddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
payload := []byte("Hello!")
|
||||
_, err = c.Write(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf [256]byte
|
||||
n, addr, err := ln.RawConn.ReadFrom(buf[:])
|
||||
if !bytes.Equal(payload, buf[:n]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload, buf[:n])
|
||||
}
|
||||
if addr.String() != c.LocalAddr().String() {
|
||||
t.Errorf("expected addr of %v; got %v", c.LocalAddr(), addr.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongReadWriteC2S(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
var payload [10485760]byte
|
||||
for i := range payload {
|
||||
payload[i] = byte(rand.Int())
|
||||
}
|
||||
|
||||
rch := make(chan []byte)
|
||||
ech := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
defer c.Close()
|
||||
_, err := c.Write(payload[:])
|
||||
if err != nil {
|
||||
ech <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
b, err := ioutil.ReadAll(s)
|
||||
if err != nil {
|
||||
ech <- err
|
||||
rch <- nil
|
||||
} else {
|
||||
ech <- nil
|
||||
rch <- b
|
||||
}
|
||||
}()
|
||||
|
||||
err = <-ech
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := <-rch
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(r, payload[:]) {
|
||||
t.Errorf("expected payload of %d; got %d", len(payload[:]), len(r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongReadWriteS2C(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
var payload [10485760]byte
|
||||
for i := range payload {
|
||||
payload[i] = byte(rand.Int())
|
||||
}
|
||||
|
||||
rch := make(chan []byte)
|
||||
ech := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
defer s.Close()
|
||||
_, err := s.Write(payload[:])
|
||||
if err != nil {
|
||||
ech <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
b, err := ioutil.ReadAll(c)
|
||||
if err != nil {
|
||||
ech <- err
|
||||
rch <- nil
|
||||
} else {
|
||||
ech <- nil
|
||||
rch <- b
|
||||
}
|
||||
}()
|
||||
|
||||
err = <-ech
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := <-rch
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(r, payload[:]) {
|
||||
t.Errorf("expected payload of %d; got %d", len(payload[:]), len(r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccept(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
_, err = ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptDeadline(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
err = ln.SetDeadline(time.Now().Add(time.Millisecond))
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptClosedListener(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ln.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialer(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
d := Dialer{}
|
||||
c, err := d.Dial("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
}
|
||||
|
||||
func TestDialerAddrs(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
laddr, err := ResolveUTPAddr("utp", "127.0.0.1:45678")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := Dialer{LocalAddr: laddr}
|
||||
c1, err := d.Dial("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c1.Close()
|
||||
|
||||
c2, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c2.Close()
|
||||
|
||||
eq := func(a, b net.Addr) bool {
|
||||
return a.String() == b.String()
|
||||
}
|
||||
|
||||
if !eq(d.LocalAddr, c2.RemoteAddr()) {
|
||||
t.Fatal("dialer.LocalAddr not equal to c2.RemoteAddr ")
|
||||
}
|
||||
if !eq(c1.LocalAddr(), c2.RemoteAddr()) {
|
||||
t.Fatal("c1.LocalAddr not equal to c2.RemoteAddr ")
|
||||
}
|
||||
if !eq(c2.LocalAddr(), c1.RemoteAddr()) {
|
||||
t.Fatal("c2.LocalAddr not equal to c1.RemoteAddr ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialerTimeout(t *testing.T) {
|
||||
timeout := time.Millisecond * 200
|
||||
d := Dialer{Timeout: timeout}
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
_, err := d.Dial("utp", "127.0.0.1:34567")
|
||||
if err == nil {
|
||||
t.Fatal("should not connect")
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout * 2):
|
||||
t.Fatal("should have ended already")
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketBinary(t *testing.T) {
|
||||
h := header{
|
||||
typ: st_fin,
|
||||
ver: version,
|
||||
id: 100,
|
||||
t: 50000,
|
||||
diff: 10000,
|
||||
wnd: 65535,
|
||||
seq: 100,
|
||||
ack: 200,
|
||||
}
|
||||
|
||||
e := []extension{
|
||||
extension{
|
||||
typ: ext_selective_ack,
|
||||
payload: []byte{0, 1, 0, 1},
|
||||
},
|
||||
extension{
|
||||
typ: ext_selective_ack,
|
||||
payload: []byte{100, 0, 200, 0},
|
||||
},
|
||||
}
|
||||
|
||||
p := packet{
|
||||
header: h,
|
||||
ext: e,
|
||||
payload: []byte("abcdefg"),
|
||||
}
|
||||
|
||||
b, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p2 := packet{payload: make([]byte, 0, mss)}
|
||||
err = p2.UnmarshalBinary(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(p, p2) {
|
||||
t.Errorf("expected packet of %v; got %v", p, p2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalShortPacket(t *testing.T) {
|
||||
b := make([]byte, 18)
|
||||
p := packet{}
|
||||
err := p.UnmarshalBinary(b)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("UnmarshalBinary should fail")
|
||||
} else if err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteOnClosedChannel(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
_, err := c.Write([]byte{100})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestReadOnClosedChannel(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
var buf [16]byte
|
||||
_, err := c.Read(buf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestPacketBuffer(t *testing.T) {
|
||||
size := 12
|
||||
b := newPacketBuffer(12, 1)
|
||||
|
||||
if b.space() != size {
|
||||
t.Errorf("expected space == %d; got %d", size, b.space())
|
||||
}
|
||||
|
||||
for i := 1; i <= size; i++ {
|
||||
b.push(&packet{header: header{seq: uint16(i)}})
|
||||
}
|
||||
|
||||
if b.space() != 0 {
|
||||
t.Errorf("expected space == 0; got %d", b.space())
|
||||
}
|
||||
|
||||
a := []byte{255, 7}
|
||||
ack := b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
err := b.push(&packet{header: header{seq: 15}})
|
||||
if err == nil {
|
||||
t.Fatal("push should fail")
|
||||
}
|
||||
|
||||
all := b.all()
|
||||
if len(all) != size {
|
||||
t.Errorf("expected %d packets sequence; got %d", size, len(all))
|
||||
}
|
||||
|
||||
f := b.fetch(6)
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
|
||||
b.compact()
|
||||
|
||||
err = b.push(&packet{header: header{seq: 15}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = b.push(&packet{header: header{seq: 17}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 7; i <= size; i++ {
|
||||
f := b.fetch(uint16(i))
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
}
|
||||
|
||||
a = []byte{128, 2}
|
||||
ack = b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 2 {
|
||||
t.Errorf("expected 2 packets sequence; got %d", len(all))
|
||||
}
|
||||
|
||||
b.compact()
|
||||
if b.space() != 9 {
|
||||
t.Errorf("expected space == 9; got %d", b.space())
|
||||
}
|
||||
|
||||
ack = b.generateSelectiveACK()
|
||||
b.processSelectiveACK(ack)
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 1 {
|
||||
t.Errorf("expected size == 1; got %d", len(all))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketBufferBoundary(t *testing.T) {
|
||||
begin := math.MaxUint16 - 3
|
||||
b := newPacketBuffer(12, begin)
|
||||
for i := begin; i != 5; i = (i + 1) % (math.MaxUint16 + 1) {
|
||||
err := b.push(&packet{header: header{seq: uint16(i)}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimedBufferNode(t *testing.T) {
|
||||
b := timedBuffer{d: time.Millisecond * 100}
|
||||
b.push(100)
|
||||
b.push(200)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
b.push(300)
|
||||
b.push(400)
|
||||
m := b.min()
|
||||
if m != 300 {
|
||||
t.Errorf("expected min == 300; got %d", m)
|
||||
}
|
||||
}
|
||||
13
Godeps/_workspace/src/github.com/jbenet/go-base58/LICENSE
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/jbenet/go-base58/LICENSE
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
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.
|
||||
66
Godeps/_workspace/src/github.com/jbenet/go-base58/README.md
generated
vendored
Normal file
66
Godeps/_workspace/src/github.com/jbenet/go-base58/README.md
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
# go-base58
|
||||
|
||||
I extracted this package from https://github.com/conformal/btcutil to provide a simple base58 package that
|
||||
- defaults to base58-check (btc)
|
||||
- and allows using different alphabets.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
b58 "github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
func main() {
|
||||
buf := []byte{255, 254, 253, 252}
|
||||
fmt.Printf("buffer: %v\n", buf)
|
||||
|
||||
str := b58.Encode(buf)
|
||||
fmt.Printf("encoded: %s\n", str)
|
||||
|
||||
buf2 := b58.Decode(str)
|
||||
fmt.Printf("decoded: %v\n", buf2)
|
||||
}
|
||||
```
|
||||
|
||||
### Another alphabet
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
b58 "github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
const BogusAlphabet = "ZYXWVUTSRQPNMLKJHGFEDCBAzyxwvutsrqponmkjihgfedcba987654321"
|
||||
|
||||
|
||||
func encdec(alphabet string) {
|
||||
fmt.Printf("using: %s\n", alphabet)
|
||||
|
||||
buf := []byte{255, 254, 253, 252}
|
||||
fmt.Printf("buffer: %v\n", buf)
|
||||
|
||||
str := b58.EncodeAlphabet(buf, alphabet)
|
||||
fmt.Printf("encoded: %s\n", str)
|
||||
|
||||
buf2 := b58.DecodeAlphabet(str, alphabet)
|
||||
fmt.Printf("decoded: %v\n\n", buf2)
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
encdec(b58.BTCAlphabet)
|
||||
encdec(b58.FlickrAlphabet)
|
||||
encdec(BogusAlphabet)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Package base58 (and the original btcutil) are licensed under the ISC License.
|
||||
90
Godeps/_workspace/src/github.com/jbenet/go-base58/base58.go
generated
vendored
Normal file
90
Godeps/_workspace/src/github.com/jbenet/go-base58/base58.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
// Modified by Juan Benet (juan@benet.ai)
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||
const BTCAlphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
const FlickrAlphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
||||
|
||||
var bigRadix = big.NewInt(58)
|
||||
var bigZero = big.NewInt(0)
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice, using BTCAlphabet
|
||||
func Decode(b string) []byte {
|
||||
return DecodeAlphabet(b, BTCAlphabet)
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string, using BTCAlphabet
|
||||
func Encode(b []byte) string {
|
||||
return EncodeAlphabet(b, BTCAlphabet)
|
||||
}
|
||||
|
||||
// DecodeAlphabet decodes a modified base58 string to a byte slice, using alphabet.
|
||||
func DecodeAlphabet(b, alphabet string) []byte {
|
||||
answer := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
tmp := strings.IndexAny(alphabet, string(b[i]))
|
||||
if tmp == -1 {
|
||||
return []byte("")
|
||||
}
|
||||
idx := big.NewInt(int64(tmp))
|
||||
tmp1 := big.NewInt(0)
|
||||
tmp1.Mul(j, idx)
|
||||
|
||||
answer.Add(answer, tmp1)
|
||||
j.Mul(j, bigRadix)
|
||||
}
|
||||
|
||||
tmpval := answer.Bytes()
|
||||
|
||||
var numZeros int
|
||||
for numZeros = 0; numZeros < len(b); numZeros++ {
|
||||
if b[numZeros] != alphabet[0] {
|
||||
break
|
||||
}
|
||||
}
|
||||
flen := numZeros + len(tmpval)
|
||||
val := make([]byte, flen, flen)
|
||||
copy(val[numZeros:], tmpval)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string, using alphabet
|
||||
func EncodeAlphabet(b []byte, alphabet string) string {
|
||||
x := new(big.Int)
|
||||
x.SetBytes(b)
|
||||
|
||||
answer := make([]byte, 0, len(b)*136/100)
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
mod := new(big.Int)
|
||||
x.DivMod(x, bigRadix, mod)
|
||||
answer = append(answer, alphabet[mod.Int64()])
|
||||
}
|
||||
|
||||
// leading zero bytes
|
||||
for _, i := range b {
|
||||
if i != 0 {
|
||||
break
|
||||
}
|
||||
answer = append(answer, alphabet[0])
|
||||
}
|
||||
|
||||
// reverse
|
||||
alen := len(answer)
|
||||
for i := 0; i < alen/2; i++ {
|
||||
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
||||
}
|
||||
|
||||
return string(answer)
|
||||
}
|
||||
96
Godeps/_workspace/src/github.com/jbenet/go-base58/base58_test.go
generated
vendored
Normal file
96
Godeps/_workspace/src/github.com/jbenet/go-base58/base58_test.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var stringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"", ""},
|
||||
{" ", "Z"},
|
||||
{"-", "n"},
|
||||
{"0", "q"},
|
||||
{"1", "r"},
|
||||
{"-1", "4SU"},
|
||||
{"11", "4k8"},
|
||||
{"abc", "ZiCa"},
|
||||
{"1234598760", "3mJr7AoUXx2Wqd"},
|
||||
{"abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f"},
|
||||
{"00000000000000000000000000000000000000000000000000000000000000", "3sN2THZeE9Eh9eYrwkvZqNstbHGvrxSAM7gXUXvyFQP8XvQLUqNCS27icwUeDT7ckHm4FUHM2mTVh1vbLmk7y"},
|
||||
}
|
||||
|
||||
var invalidStringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"0", ""},
|
||||
{"O", ""},
|
||||
{"I", ""},
|
||||
{"l", ""},
|
||||
{"3mJr0", ""},
|
||||
{"O3yxU", ""},
|
||||
{"3sNI", ""},
|
||||
{"4kl8", ""},
|
||||
{"0OIl", ""},
|
||||
{"!@#$%^&*()-_=+~`", ""},
|
||||
}
|
||||
|
||||
var hexTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"61", "2g"},
|
||||
{"626262", "a3gV"},
|
||||
{"636363", "aPEr"},
|
||||
{"73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"},
|
||||
{"00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"},
|
||||
{"516b6fcd0f", "ABnLTmg"},
|
||||
{"bf4f89001e670274dd", "3SEo3LWLoPntC"},
|
||||
{"572e4794", "3EFU7m"},
|
||||
{"ecac89cad93923c02321", "EJDM8drfXA6uyA"},
|
||||
{"10c8511e", "Rt5zm"},
|
||||
{"00000000000000000000", "1111111111"},
|
||||
}
|
||||
|
||||
func TestBase58(t *testing.T) {
|
||||
// Base58Encode tests
|
||||
for x, test := range stringTests {
|
||||
tmp := []byte(test.in)
|
||||
if res := Encode(tmp); res != test.out {
|
||||
t.Errorf("Base58Encode test #%d failed: got: %s want: %s",
|
||||
x, res, test.out)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Base58Decode tests
|
||||
for x, test := range hexTests {
|
||||
b, err := hex.DecodeString(test.in)
|
||||
if err != nil {
|
||||
t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in)
|
||||
continue
|
||||
}
|
||||
if res := Decode(test.out); bytes.Equal(res, b) != true {
|
||||
t.Errorf("Base58Decode test #%d failed: got: %q want: %q",
|
||||
x, res, test.in)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Base58Decode with invalid input
|
||||
for x, test := range invalidStringTests {
|
||||
if res := Decode(test.in); string(res) != test.out {
|
||||
t.Errorf("Base58Decode invalidString test #%d failed: got: %q want: %q",
|
||||
x, res, test.out)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Godeps/_workspace/src/github.com/jbenet/go-base58/doc.go
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/jbenet/go-base58/doc.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package base58 provides base58-check encoding.
|
||||
The alphabet is modifyiable for
|
||||
|
||||
Base58 Usage
|
||||
|
||||
To decode a base58 string:
|
||||
|
||||
rawData := base58.Base58Decode(encodedData)
|
||||
|
||||
Similarly, to encode the same data:
|
||||
|
||||
encodedData := base58.Base58Encode(rawData)
|
||||
|
||||
*/
|
||||
package base58
|
||||
3
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/.travis.yml
generated
vendored
3
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/.travis.yml
generated
vendored
@ -1,10 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- release
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
- go test -race -cpu=5 -v ./...
|
||||
|
||||
100
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
100
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
@ -2,10 +2,13 @@ package multiaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func stringToBytes(s string) ([]byte, error) {
|
||||
@ -31,17 +34,19 @@ func stringToBytes(s string) ([]byte, error) {
|
||||
b = append(b, CodeToVarint(p.Code)...)
|
||||
sp = sp[1:]
|
||||
|
||||
if p.Size > 0 {
|
||||
if len(sp) < 1 {
|
||||
return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
|
||||
}
|
||||
a, err := addressStringToBytes(p, sp[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
||||
}
|
||||
b = append(b, a...)
|
||||
sp = sp[1:]
|
||||
if p.Size == 0 { // no length.
|
||||
continue
|
||||
}
|
||||
|
||||
if len(sp) < 1 {
|
||||
return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
|
||||
}
|
||||
a, err := addressStringToBytes(p, sp[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
||||
}
|
||||
b = append(b, a...)
|
||||
sp = sp[1:]
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
@ -51,7 +56,14 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
ret = ""
|
||||
err = e.(error)
|
||||
switch e := e.(type) {
|
||||
case error:
|
||||
err = e
|
||||
case string:
|
||||
err = errors.New(e)
|
||||
default:
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@ -65,20 +77,38 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||
if p.Code == 0 {
|
||||
return "", fmt.Errorf("no protocol with code %d", code)
|
||||
}
|
||||
s = strings.Join([]string{s, "/", p.Name}, "")
|
||||
s += "/" + p.Name
|
||||
|
||||
if p.Size > 0 {
|
||||
a := addressBytesToString(p, b[:(p.Size/8)])
|
||||
if len(a) > 0 {
|
||||
s = strings.Join([]string{s, "/", a}, "")
|
||||
}
|
||||
b = b[(p.Size / 8):]
|
||||
if p.Size == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
size := sizeForAddr(p, b)
|
||||
a, err := addressBytesToString(p, b[:size])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(a) > 0 {
|
||||
s += "/" + a
|
||||
}
|
||||
b = b[size:]
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func sizeForAddr(p Protocol, b []byte) int {
|
||||
switch {
|
||||
case p.Size > 0:
|
||||
return (p.Size / 8)
|
||||
case p.Size == 0:
|
||||
return 0
|
||||
default:
|
||||
size, n := ReadVarintCode(b)
|
||||
return size + n
|
||||
}
|
||||
}
|
||||
|
||||
func bytesSplit(b []byte) (ret [][]byte, err error) {
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
@ -96,7 +126,8 @@ func bytesSplit(b []byte) (ret [][]byte, err error) {
|
||||
return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
|
||||
}
|
||||
|
||||
length := n + (p.Size / 8)
|
||||
size := sizeForAddr(p, b[n:])
|
||||
length := n + size
|
||||
ret = append(ret, b[:length])
|
||||
b = b[length:]
|
||||
}
|
||||
@ -133,23 +164,46 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, uint16(i))
|
||||
return b, nil
|
||||
|
||||
case P_IPFS: // ipfs
|
||||
// the address is a varint prefixed multihash string representation
|
||||
m, err := mh.FromB58String(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err)
|
||||
}
|
||||
size := CodeToVarint(len(m))
|
||||
b := append(size, m...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name)
|
||||
}
|
||||
|
||||
func addressBytesToString(p Protocol, b []byte) string {
|
||||
func addressBytesToString(p Protocol, b []byte) (string, error) {
|
||||
switch p.Code {
|
||||
|
||||
// ipv4,6
|
||||
case P_IP4, P_IP6:
|
||||
return net.IP(b).String()
|
||||
return net.IP(b).String(), nil
|
||||
|
||||
// tcp udp dccp sctp
|
||||
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
||||
i := binary.BigEndian.Uint16(b)
|
||||
return strconv.Itoa(int(i))
|
||||
return strconv.Itoa(int(i)), nil
|
||||
|
||||
case P_IPFS: // ipfs
|
||||
// the address is a varint-prefixed multihash string representation
|
||||
size, n := ReadVarintCode(b)
|
||||
b = b[n:]
|
||||
if len(b) != size {
|
||||
panic("inconsistent lengths")
|
||||
}
|
||||
m, err := mh.Cast(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.B58String(), nil
|
||||
}
|
||||
|
||||
return ""
|
||||
return "", fmt.Errorf("unknown protocol")
|
||||
}
|
||||
|
||||
6
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
6
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
@ -64,6 +64,7 @@ func (m *multiaddr) Protocols() []Protocol {
|
||||
}
|
||||
}()
|
||||
|
||||
size := 0
|
||||
ps := []Protocol{}
|
||||
b := m.bytes[:]
|
||||
for len(b) > 0 {
|
||||
@ -75,7 +76,10 @@ func (m *multiaddr) Protocols() []Protocol {
|
||||
panic(fmt.Errorf("no protocol with code %d", b[0]))
|
||||
}
|
||||
ps = append(ps, p)
|
||||
b = b[n+(p.Size/8):]
|
||||
b = b[n:]
|
||||
|
||||
size = sizeForAddr(p, b)
|
||||
b = b[size:]
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
12
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
12
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
@ -32,11 +32,13 @@ func TestConstructFails(t *testing.T) {
|
||||
"/ip4/127.0.0.1/udp",
|
||||
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
|
||||
"/ip4/127.0.0.1/tcp",
|
||||
"/ip4/127.0.0.1/ipfs",
|
||||
"/ip4/127.0.0.1/ipfs/tcp",
|
||||
}
|
||||
|
||||
for _, a := range cases {
|
||||
if _, err := NewMultiaddr(a); err == nil {
|
||||
t.Errorf("should have failed: %s", a)
|
||||
t.Errorf("should have failed: %s - %s", a, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,18 +57,24 @@ func TestConstructSucceeds(t *testing.T) {
|
||||
"/sctp/1234",
|
||||
"/udp/65535",
|
||||
"/tcp/65535",
|
||||
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
||||
"/udp/1234/sctp/1234",
|
||||
"/udp/1234/udt",
|
||||
"/udp/1234/utp",
|
||||
"/tcp/1234/http",
|
||||
"/tcp/1234/https",
|
||||
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
||||
"/ip4/127.0.0.1/udp/1234",
|
||||
"/ip4/127.0.0.1/udp/0",
|
||||
"/ip4/127.0.0.1/tcp/1234",
|
||||
"/ip4/127.0.0.1/tcp/1234/",
|
||||
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
||||
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
|
||||
}
|
||||
|
||||
for _, a := range cases {
|
||||
if _, err := NewMultiaddr(a); err != nil {
|
||||
t.Errorf("should have succeeded: %s", a)
|
||||
t.Errorf("should have succeeded: %s -- %s", a, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
1
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
@ -7,5 +7,6 @@ code size name
|
||||
132 16 sctp
|
||||
301 0 udt
|
||||
302 0 utp
|
||||
421 V ipfs
|
||||
480 0 http
|
||||
443 0 https
|
||||
|
||||
|
31
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
31
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
// Protocol is a Multiaddr protocol description structure.
|
||||
type Protocol struct {
|
||||
Code int
|
||||
Size int
|
||||
Size int // a size of -1 indicates a length-prefixed variable size
|
||||
Name string
|
||||
VCode []byte
|
||||
}
|
||||
@ -19,14 +19,22 @@ type Protocol struct {
|
||||
// 2. ensuring errors in the csv don't screw up code.
|
||||
// 3. changing a number has to happen in two places.
|
||||
const (
|
||||
P_IP4 = 4
|
||||
P_TCP = 6
|
||||
P_UDP = 17
|
||||
P_DCCP = 33
|
||||
P_IP6 = 41
|
||||
P_SCTP = 132
|
||||
P_UTP = 301
|
||||
P_UDT = 302
|
||||
P_IP4 = 4
|
||||
P_TCP = 6
|
||||
P_UDP = 17
|
||||
P_DCCP = 33
|
||||
P_IP6 = 41
|
||||
P_SCTP = 132
|
||||
P_UTP = 301
|
||||
P_UDT = 302
|
||||
P_IPFS = 421
|
||||
P_HTTP = 480
|
||||
P_HTTPS = 443
|
||||
)
|
||||
|
||||
// These are special sizes
|
||||
const (
|
||||
LengthPrefixedVarSize = -1
|
||||
)
|
||||
|
||||
// Protocols is the list of multiaddr protocols supported by this module.
|
||||
@ -40,8 +48,9 @@ var Protocols = []Protocol{
|
||||
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)},
|
||||
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)},
|
||||
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)},
|
||||
// {480, 0, "http"},
|
||||
// {443, 0, "https"},
|
||||
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)},
|
||||
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS)},
|
||||
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS)},
|
||||
}
|
||||
|
||||
// ProtocolWithName returns the Protocol description with given string name.
|
||||
|
||||
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/.travis.yml
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- release
|
||||
- tip
|
||||
|
||||
script:
|
||||
- make test
|
||||
|
||||
env: TEST_VERBOSE=1
|
||||
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/jbenet/go-multihash/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
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.
|
||||
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/Makefile
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/jbenet/go-multihash/Makefile
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
test: go_test other_tests
|
||||
|
||||
other_tests:
|
||||
cd test && make test
|
||||
|
||||
go_test: go_deps
|
||||
go test -race -cpu=5 -v ./...
|
||||
|
||||
go_deps:
|
||||
go get golang.org/x/crypto/sha3
|
||||
go get github.com/jbenet/go-base58
|
||||
45
Godeps/_workspace/src/github.com/jbenet/go-multihash/README.md
generated
vendored
Normal file
45
Godeps/_workspace/src/github.com/jbenet/go-multihash/README.md
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
# go-multihash
|
||||
|
||||

|
||||
|
||||
[multihash](//github.com/jbenet/multihash) implementation in Go.
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// ignores errors for simplicity.
|
||||
// don't do that at home.
|
||||
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := multihash.EncodeName(buf, "sha1");
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex);
|
||||
|
||||
o, _ := multihash.Decode(mhbuf);
|
||||
mhhex = hex.EncodeToString(o.Digest);
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex);
|
||||
}
|
||||
```
|
||||
|
||||
Run [test/foo.go](test/foo.go)
|
||||
|
||||
```
|
||||
> cd test/
|
||||
> go build
|
||||
> ./test
|
||||
hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
Normal file
79
Godeps/_workspace/src/github.com/jbenet/go-multihash/io.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Reader is an io.Reader wrapper that exposes a function
|
||||
// to read a whole multihash, parse it, and return it.
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
|
||||
ReadMultihash() (Multihash, error)
|
||||
}
|
||||
|
||||
// Writer is an io.Writer wrapper that exposes a function
|
||||
// to write a whole multihash.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
|
||||
WriteMultihash(Multihash) error
|
||||
}
|
||||
|
||||
// NewReader wraps an io.Reader with a multihash.Reader
|
||||
func NewReader(r io.Reader) Reader {
|
||||
return &mhReader{r}
|
||||
}
|
||||
|
||||
// NewWriter wraps an io.Writer with a multihash.Writer
|
||||
func NewWriter(w io.Writer) Writer {
|
||||
return &mhWriter{w}
|
||||
}
|
||||
|
||||
type mhReader struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (r *mhReader) Read(buf []byte) (n int, err error) {
|
||||
return r.r.Read(buf)
|
||||
}
|
||||
|
||||
func (r *mhReader) ReadMultihash() (Multihash, error) {
|
||||
mhhdr := make([]byte, 2)
|
||||
if _, err := io.ReadFull(r.r, mhhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// first byte is the algo, the second is the length.
|
||||
|
||||
// (varints someday...)
|
||||
length := uint(mhhdr[1])
|
||||
|
||||
if length > 127 {
|
||||
return nil, fmt.Errorf("varints not yet supported (length is %d)", length)
|
||||
}
|
||||
|
||||
buf := make([]byte, length+2)
|
||||
buf[0] = mhhdr[0]
|
||||
buf[1] = mhhdr[1]
|
||||
|
||||
if _, err := io.ReadFull(r.r, buf[2:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Cast(buf)
|
||||
}
|
||||
|
||||
type mhWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *mhWriter) Write(buf []byte) (n int, err error) {
|
||||
return w.w.Write(buf)
|
||||
}
|
||||
|
||||
func (w *mhWriter) WriteMultihash(m Multihash) error {
|
||||
_, err := w.w.Write([]byte(m))
|
||||
return err
|
||||
}
|
||||
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/jbenet/go-multihash/io_test.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf.Write([]byte(m))
|
||||
}
|
||||
|
||||
r := NewReader(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h2, err := r.ReadMultihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(h, h2) {
|
||||
t.Error("h and h2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := NewWriter(&buf)
|
||||
|
||||
for _, tc := range testCases {
|
||||
m, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := w.WriteMultihash(m); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
buf2 := make([]byte, len(m))
|
||||
if _, err := io.ReadFull(&buf, buf2); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(m, buf2) {
|
||||
t.Error("m and buf2 should be equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
Normal file
188
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
b58 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-base58"
|
||||
)
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrUnknownCode = errors.New("unknown multihash code")
|
||||
ErrTooShort = errors.New("multihash too short. must be > 3 bytes")
|
||||
ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
|
||||
ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
|
||||
)
|
||||
|
||||
// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
|
||||
type ErrInconsistentLen struct {
|
||||
dm *DecodedMultihash
|
||||
}
|
||||
|
||||
func (e ErrInconsistentLen) Error() string {
|
||||
return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
|
||||
}
|
||||
|
||||
// constants
|
||||
const (
|
||||
SHA1 = 0x11
|
||||
SHA2_256 = 0x12
|
||||
SHA2_512 = 0x13
|
||||
SHA3 = 0x14
|
||||
BLAKE2B = 0x40
|
||||
BLAKE2S = 0x41
|
||||
)
|
||||
|
||||
// Names maps the name of a hash to the code
|
||||
var Names = map[string]int{
|
||||
"sha1": SHA1,
|
||||
"sha2-256": SHA2_256,
|
||||
"sha2-512": SHA2_512,
|
||||
"sha3": SHA3,
|
||||
"blake2b": BLAKE2B,
|
||||
"blake2s": BLAKE2S,
|
||||
}
|
||||
|
||||
// Codes maps a hash code to it's name
|
||||
var Codes = map[int]string{
|
||||
SHA1: "sha1",
|
||||
SHA2_256: "sha2-256",
|
||||
SHA2_512: "sha2-512",
|
||||
SHA3: "sha3",
|
||||
BLAKE2B: "blake2b",
|
||||
BLAKE2S: "blake2s",
|
||||
}
|
||||
|
||||
// DefaultLengths maps a hash code to it's default length
|
||||
var DefaultLengths = map[int]int{
|
||||
SHA1: 20,
|
||||
SHA2_256: 32,
|
||||
SHA2_512: 64,
|
||||
SHA3: 64,
|
||||
BLAKE2B: 64,
|
||||
BLAKE2S: 32,
|
||||
}
|
||||
|
||||
type DecodedMultihash struct {
|
||||
Code int
|
||||
Name string
|
||||
Length int
|
||||
Digest []byte
|
||||
}
|
||||
|
||||
type Multihash []byte
|
||||
|
||||
func (m *Multihash) HexString() string {
|
||||
return hex.EncodeToString([]byte(*m))
|
||||
}
|
||||
|
||||
func (m *Multihash) String() string {
|
||||
return m.HexString()
|
||||
}
|
||||
|
||||
func FromHexString(s string) (Multihash, error) {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return Multihash{}, err
|
||||
}
|
||||
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func (m Multihash) B58String() string {
|
||||
return b58.Encode([]byte(m))
|
||||
}
|
||||
|
||||
func FromB58String(s string) (m Multihash, err error) {
|
||||
// panic handler, in case we try accessing bytes incorrectly.
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
m = Multihash{}
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
//b58 smells like it can panic...
|
||||
b := b58.Decode(s)
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func Cast(buf []byte) (Multihash, error) {
|
||||
dm, err := Decode(buf)
|
||||
if err != nil {
|
||||
return Multihash{}, err
|
||||
}
|
||||
|
||||
if !ValidCode(dm.Code) {
|
||||
return Multihash{}, ErrUnknownCode
|
||||
}
|
||||
|
||||
return Multihash(buf), nil
|
||||
}
|
||||
|
||||
// Decode a hash from the given Multihash.
|
||||
func Decode(buf []byte) (*DecodedMultihash, error) {
|
||||
|
||||
if len(buf) < 3 {
|
||||
return nil, ErrTooShort
|
||||
}
|
||||
|
||||
if len(buf) > 129 {
|
||||
return nil, ErrTooLong
|
||||
}
|
||||
|
||||
dm := &DecodedMultihash{
|
||||
Code: int(uint8(buf[0])),
|
||||
Name: Codes[int(uint8(buf[0]))],
|
||||
Length: int(uint8(buf[1])),
|
||||
Digest: buf[2:],
|
||||
}
|
||||
|
||||
if len(dm.Digest) != dm.Length {
|
||||
return nil, ErrInconsistentLen{dm}
|
||||
}
|
||||
|
||||
return dm, nil
|
||||
}
|
||||
|
||||
// Encode a hash digest along with the specified function code.
|
||||
// Note: the length is derived from the length of the digest itself.
|
||||
func Encode(buf []byte, code int) ([]byte, error) {
|
||||
|
||||
if !ValidCode(code) {
|
||||
return nil, ErrUnknownCode
|
||||
}
|
||||
|
||||
if len(buf) > 127 {
|
||||
return nil, ErrLenNotSupported
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(code))
|
||||
pre[1] = byte(uint8(len(buf)))
|
||||
return append(pre, buf...), nil
|
||||
}
|
||||
|
||||
func EncodeName(buf []byte, name string) ([]byte, error) {
|
||||
return Encode(buf, Names[name])
|
||||
}
|
||||
|
||||
// ValidCode checks whether a multihash code is valid.
|
||||
func ValidCode(code int) bool {
|
||||
if AppCode(code) {
|
||||
return true
|
||||
}
|
||||
|
||||
if _, ok := Codes[code]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AppCode checks whether a multihash code is part of the App range.
|
||||
func AppCode(code int) bool {
|
||||
return code >= 0 && code < 0x10
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/.gitignore
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
multihash
|
||||
116
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/README.md
generated
vendored
Normal file
116
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/README.md
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
# multihash tool
|
||||
|
||||
The `multihash` tool uses `go-multihash` to hash things much like `shasum`.
|
||||
|
||||
Warning: this is a **multihash** tool! Its digests follow the [multihash](https://github.com/jbenet/multihash) format.
|
||||
|
||||
### Install
|
||||
|
||||
```
|
||||
go get github.com/jbenet/go-multihash/multihash
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
> multihash -h
|
||||
usage: ./multihash [options] [FILE]
|
||||
Print or check multihash checksums.
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
Options:
|
||||
-a="sha2-256": one of: sha1, sha2-256, sha2-512, sha3 (shorthand)
|
||||
-algorithm="sha2-256": one of: sha1, sha2-256, sha2-512, sha3
|
||||
-c="": check checksum matches (shorthand)
|
||||
-check="": check checksum matches
|
||||
-e="base58": one of: raw, hex, base58, base64 (shorthand)
|
||||
-encoding="base58": one of: raw, hex, base58, base64
|
||||
-l=-1: checksums length in bits (truncate). -1 is default (shorthand)
|
||||
-length=-1: checksums length in bits (truncate). -1 is default
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
#### Input
|
||||
|
||||
```sh
|
||||
# from stdin
|
||||
> multihash < main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
|
||||
# from file
|
||||
> ./multihash main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
|
||||
# from stdin "filename"
|
||||
> multihash - < main.go
|
||||
QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8
|
||||
```
|
||||
|
||||
#### Algorithms
|
||||
|
||||
```sh
|
||||
> multihash -a ?
|
||||
error: algorithm '?' not one of: sha1, sha2-256, sha2-512, sha3
|
||||
|
||||
> multihash -a sha1 < main.go
|
||||
5drkbcqJUo6fZVvcZJeVEVWAgndvLm
|
||||
|
||||
> multihash -a sha2-256 < main.go
|
||||
QmcK3s36goo9v2HYcfTrDKKwxaxmJJ59etodQQFYsL5T5N
|
||||
|
||||
> multihash -a sha2-512 < main.go
|
||||
8VuDcW4CooyPQA8Cc4eYpwjhyDJZqu5m5ZMDFzWULYsVS8d119JaGeNWsZbZ2ZG2kPtbrMx31MidokCigaD65yUPAs
|
||||
|
||||
> multihash -a sha3 < main.go
|
||||
8tWDCTfAX24DYmzNixTj2ARJkqwRG736VHx5aJppmqRjhW9QT1EuTgKUmu9Pmunzq292jzPKxb2VxSsTXmjFY1HD3B
|
||||
```
|
||||
|
||||
#### Encodings
|
||||
|
||||
```sh
|
||||
> multihash -e raw < main.go
|
||||
Ϛ<><CF9A><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD>5 S<><53>WG><3E><><EFBFBD>_<EFBFBD><5F>]g<><67><EFBFBD><EFBFBD><EFBFBD>u
|
||||
|
||||
> multihash -e hex < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
|
||||
> multihash -e base64 < main.go
|
||||
EiDPmqK4o4ubSdE1CVOQBZpXRz6XrOtfyuJdZ6i2/rWCdQ==
|
||||
|
||||
> multihash -e base58 < main.go
|
||||
Qmf1QjEXDmqBm7RqHKqFGNUyhzUjnX7cmgKMrGzzPceZDQ
|
||||
```
|
||||
|
||||
#### Digest Length
|
||||
|
||||
```sh
|
||||
# we're outputing hex (good byte alignment) to show the codes changing
|
||||
# notice the multihash code (first 2 chars) differs!
|
||||
> multihash -e hex -a sha2-256 -l 256 < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
> multihash -e hex -a sha2-512 -l 256 < main.go
|
||||
132047a4b6c629f5545f529b0ff461dc09119969f3593186277a1cc7a8ea3560a6f1
|
||||
> multihash -e hex -a sha3 -l 256 < main.go
|
||||
14206b9222a1a47939e665261bd2b5573e55e7988675223adde73c1011066ad66335
|
||||
|
||||
# notice the multihash length (next 2 chars) differs!
|
||||
> multihash -e hex -a sha2-256 -l 256 < main.go
|
||||
1220cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d67a8b6feb58275
|
||||
> multihash -e hex -a sha2-256 -l 200 < main.go
|
||||
1219cf9aa2b8a38b9b49d135095390059a57473e97aceb5fcae25d
|
||||
```
|
||||
|
||||
#### Verify Checksum
|
||||
|
||||
```sh
|
||||
> multihash -c QmRZxt2b1FVZPNqd8hsiykDL3TdBDeTSPX9Kv46HmX4Gx8 < main.go
|
||||
OK checksums match (-q for no output)
|
||||
|
||||
> multihash -c QmcKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa < main.go
|
||||
error: computed checksum did not match (-q for no output)
|
||||
|
||||
# works with other arguments too
|
||||
> multihash -e hex -l 128 -c "12102ffc284a1e82bf51e567c75b2ae6edb9" < main.go
|
||||
OK checksums match (-q for no output)
|
||||
```
|
||||
40
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/coding.go
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/coding.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
base58 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-base58"
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
func Decode(encoding, digest string) (mh.Multihash, error) {
|
||||
switch encoding {
|
||||
case "raw":
|
||||
return mh.Cast([]byte(digest))
|
||||
case "hex":
|
||||
return hex.DecodeString(digest)
|
||||
case "base58":
|
||||
return base58.Decode(digest), nil
|
||||
case "base64":
|
||||
return base64.StdEncoding.DecodeString(digest)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown encoding: %s", encoding)
|
||||
}
|
||||
}
|
||||
|
||||
func Encode(encoding string, hash mh.Multihash) (string, error) {
|
||||
switch encoding {
|
||||
case "raw":
|
||||
return string(hash), nil
|
||||
case "hex":
|
||||
return hex.EncodeToString(hash), nil
|
||||
case "base58":
|
||||
return base58.Encode(hash), nil
|
||||
case "base64":
|
||||
return base64.StdEncoding.EncodeToString(hash), nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown encoding: %s", encoding)
|
||||
}
|
||||
}
|
||||
208
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/main.go
generated
vendored
Normal file
208
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash/main.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
)
|
||||
|
||||
var usage = `usage: %s [options] [FILE]
|
||||
Print or check multihash checksums.
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
Options:
|
||||
`
|
||||
|
||||
// flags
|
||||
var encodings = []string{"raw", "hex", "base58", "base64"}
|
||||
var algorithms = []string{"sha1", "sha2-256", "sha2-512", "sha3"}
|
||||
var encoding string
|
||||
var algorithm string
|
||||
var algorithmCode int
|
||||
var length int
|
||||
var checkRaw string
|
||||
var checkMh mh.Multihash
|
||||
var inputFilename string
|
||||
var quiet bool
|
||||
|
||||
// joined names
|
||||
var algoStr string
|
||||
var encStr string
|
||||
|
||||
func init() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, usage, os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
algoStr = "one of: " + strings.Join(algorithms, ", ")
|
||||
flag.StringVar(&algorithm, "algorithm", "sha2-256", algoStr)
|
||||
flag.StringVar(&algorithm, "a", "sha2-256", algoStr+" (shorthand)")
|
||||
|
||||
encStr = "one of: " + strings.Join(encodings, ", ")
|
||||
flag.StringVar(&encoding, "encoding", "base58", encStr)
|
||||
flag.StringVar(&encoding, "e", "base58", encStr+" (shorthand)")
|
||||
|
||||
checkStr := "check checksum matches"
|
||||
flag.StringVar(&checkRaw, "check", "", checkStr)
|
||||
flag.StringVar(&checkRaw, "c", "", checkStr+" (shorthand)")
|
||||
|
||||
lengthStr := "checksums length in bits (truncate). -1 is default"
|
||||
flag.IntVar(&length, "length", -1, lengthStr)
|
||||
flag.IntVar(&length, "l", -1, lengthStr+" (shorthand)")
|
||||
|
||||
quietStr := "quiet output (no newline on checksum, no error text)"
|
||||
flag.BoolVar(&quiet, "quiet", false, quietStr)
|
||||
flag.BoolVar(&quiet, "q", false, quietStr+" (shorthand)")
|
||||
}
|
||||
|
||||
func strIn(a string, set []string) bool {
|
||||
for _, s := range set {
|
||||
if s == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseFlags() error {
|
||||
flag.Parse()
|
||||
|
||||
if !strIn(algorithm, algorithms) {
|
||||
return fmt.Errorf("algorithm '%s' not %s", algorithm, algoStr)
|
||||
}
|
||||
var found bool
|
||||
algorithmCode, found = mh.Names[algorithm]
|
||||
if !found {
|
||||
return fmt.Errorf("algorithm '%s' not found (lib error, pls report).")
|
||||
}
|
||||
|
||||
if !strIn(encoding, encodings) {
|
||||
return fmt.Errorf("encoding '%s' not %s", encoding, encStr)
|
||||
}
|
||||
|
||||
if checkRaw != "" {
|
||||
var err error
|
||||
checkMh, err = Decode(encoding, checkRaw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to decode check '%s': %s", checkRaw, err)
|
||||
}
|
||||
}
|
||||
|
||||
if length >= 0 {
|
||||
if length%8 != 0 {
|
||||
return fmt.Errorf("length must be multiple of 8")
|
||||
}
|
||||
length = length / 8
|
||||
|
||||
if length > mh.DefaultLengths[algorithmCode] {
|
||||
length = mh.DefaultLengths[algorithmCode]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getInput() (io.ReadCloser, error) {
|
||||
args := flag.Args()
|
||||
|
||||
switch {
|
||||
case len(args) < 1:
|
||||
inputFilename = "-"
|
||||
return os.Stdin, nil
|
||||
case args[0] == "-":
|
||||
inputFilename = "-"
|
||||
return os.Stdin, nil
|
||||
default:
|
||||
inputFilename = args[0]
|
||||
f, err := os.Open(args[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open '%s': %s", args[0], err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
func check(h1 mh.Multihash, r io.Reader) error {
|
||||
h2, err := hash(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.Equal(h1, h2) {
|
||||
if quiet {
|
||||
os.Exit(1)
|
||||
}
|
||||
return fmt.Errorf("computed checksum did not match (-q for no output)")
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
fmt.Println("OK checksums match (-q for no output)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hash(r io.Reader) (mh.Multihash, error) {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mh.Sum(b, algorithmCode, length)
|
||||
}
|
||||
|
||||
func printHash(r io.Reader) error {
|
||||
h, err := hash(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := Encode(encoding, h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if quiet {
|
||||
fmt.Print(s)
|
||||
} else {
|
||||
fmt.Println(s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
checkErr := func(err error) {
|
||||
if err != nil {
|
||||
die("error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := parseFlags()
|
||||
checkErr(err)
|
||||
|
||||
inp, err := getInput()
|
||||
checkErr(err)
|
||||
|
||||
if checkMh != nil {
|
||||
err = check(checkMh, inp)
|
||||
checkErr(err)
|
||||
} else {
|
||||
err = printHash(inp)
|
||||
checkErr(err)
|
||||
}
|
||||
inp.Close()
|
||||
}
|
||||
|
||||
func die(v ...interface{}) {
|
||||
if !quiet {
|
||||
fmt.Fprint(os.Stderr, v...)
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
// flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
270
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
Normal file
270
Godeps/_workspace/src/github.com/jbenet/go-multihash/multihash_test.go
generated
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// maybe silly, but makes it so changing
|
||||
// the table accidentally has to happen twice.
|
||||
var tCodes = map[int]string{
|
||||
0x11: "sha1",
|
||||
0x12: "sha2-256",
|
||||
0x13: "sha2-512",
|
||||
0x14: "sha3",
|
||||
0x40: "blake2b",
|
||||
0x41: "blake2s",
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
hex string
|
||||
code int
|
||||
name string
|
||||
}
|
||||
|
||||
var testCases = []TestCase{
|
||||
TestCase{"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", 0x11, "sha1"},
|
||||
TestCase{"0beec7b5", 0x11, "sha1"},
|
||||
TestCase{"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", 0x12, "sha2-256"},
|
||||
TestCase{"2c26b46b", 0x12, "sha2-256"},
|
||||
TestCase{"0beec7b5ea3f0fdbc9", 0x40, "blake2b"},
|
||||
}
|
||||
|
||||
func (tc TestCase) Multihash() (Multihash, error) {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := make([]byte, 2+len(ob))
|
||||
b[0] = byte(uint8(tc.code))
|
||||
b[1] = byte(uint8(len(ob)))
|
||||
copy(b[2:], ob)
|
||||
return Cast(b)
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
encC, err := Encode(ob, tc.code)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(encC, nb) {
|
||||
t.Error("encoded byte mismatch: ", encC, nb)
|
||||
}
|
||||
|
||||
encN, err := EncodeName(ob, tc.name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(encN, nb) {
|
||||
t.Error("encoded byte mismatch: ", encN, nb)
|
||||
}
|
||||
|
||||
h, err := tc.Multihash()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !bytes.Equal(h, nb) {
|
||||
t.Error("Multihash func mismatch.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEncodeName() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
mhhex := hex.EncodeToString(mhbuf)
|
||||
fmt.Printf("hex: %v\n", mhhex)
|
||||
|
||||
// Output:
|
||||
// hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
dec, err := Decode(nb)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if dec.Code != tc.code {
|
||||
t.Error("decoded code mismatch: ", dec.Code, tc.code)
|
||||
}
|
||||
|
||||
if dec.Name != tc.name {
|
||||
t.Error("decoded name mismatch: ", dec.Name, tc.name)
|
||||
}
|
||||
|
||||
if dec.Length != len(ob) {
|
||||
t.Error("decoded length mismatch: ", dec.Length, len(ob))
|
||||
}
|
||||
|
||||
if !bytes.Equal(dec.Digest, ob) {
|
||||
t.Error("decoded byte mismatch: ", dec.Digest, ob)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTable(t *testing.T) {
|
||||
for k, v := range tCodes {
|
||||
if Codes[k] != v {
|
||||
t.Error("Table mismatch: ", Codes[k], v)
|
||||
}
|
||||
if Names[v] != k {
|
||||
t.Error("Table mismatch: ", Names[v], k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleDecode() {
|
||||
// ignores errors for simplicity - don't do that at home.
|
||||
buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
|
||||
mhbuf, _ := EncodeName(buf, "sha1")
|
||||
o, _ := Decode(mhbuf)
|
||||
mhhex := hex.EncodeToString(o.Digest)
|
||||
fmt.Printf("obj: %v 0x%x %d %s\n", o.Name, o.Code, o.Length, mhhex)
|
||||
|
||||
// Output:
|
||||
// obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
|
||||
}
|
||||
|
||||
func TestValidCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
_, ok := tCodes[i]
|
||||
b := AppCode(i) || ok
|
||||
|
||||
if ValidCode(i) != b {
|
||||
t.Error("ValidCode incorrect for: ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCode(t *testing.T) {
|
||||
for i := 0; i < 0xff; i++ {
|
||||
b := i >= 0 && i < 0x10
|
||||
if AppCode(i) != b {
|
||||
t.Error("AppCode incorrect for: ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCast(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
if _, err := Cast(nb); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = Cast(ob); err == nil {
|
||||
t.Error("cast failed to detect non-multihash")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHex(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
hs := hex.EncodeToString(nb)
|
||||
mh, err := FromHexString(hs)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(mh, nb) {
|
||||
t.Error("FromHexString failed", nb, mh)
|
||||
continue
|
||||
}
|
||||
|
||||
if mh.HexString() != hs {
|
||||
t.Error("Multihash.HexString failed", hs, mh.HexString)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ob, tc.code)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
tc := testCases[0]
|
||||
ob, err := hex.DecodeString(tc.hex)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
pre := make([]byte, 2)
|
||||
pre[0] = byte(uint8(tc.code))
|
||||
pre[1] = byte(uint8(len(ob)))
|
||||
nb := append(pre, ob...)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Decode(nb)
|
||||
}
|
||||
}
|
||||
72
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
Normal file
72
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
sha3 "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")
|
||||
|
||||
func Sum(data []byte, code int, length int) (Multihash, error) {
|
||||
m := Multihash{}
|
||||
err := error(nil)
|
||||
if !ValidCode(code) {
|
||||
return m, fmt.Errorf("invalid multihash code %d", code)
|
||||
}
|
||||
|
||||
var d []byte
|
||||
switch code {
|
||||
case SHA1:
|
||||
d = sumSHA1(data)
|
||||
case SHA2_256:
|
||||
d = sumSHA256(data)
|
||||
case SHA2_512:
|
||||
d = sumSHA512(data)
|
||||
case SHA3:
|
||||
d, err = sumSHA3(data)
|
||||
default:
|
||||
return m, ErrSumNotSupported
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
if length < 0 {
|
||||
var ok bool
|
||||
length, ok = DefaultLengths[code]
|
||||
if !ok {
|
||||
return m, fmt.Errorf("no default length for code %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
return Encode(d[0:length], code)
|
||||
}
|
||||
|
||||
func sumSHA1(data []byte) []byte {
|
||||
a := sha1.Sum(data)
|
||||
return a[0:20]
|
||||
}
|
||||
|
||||
func sumSHA256(data []byte) []byte {
|
||||
a := sha256.Sum256(data)
|
||||
return a[0:32]
|
||||
}
|
||||
|
||||
func sumSHA512(data []byte) []byte {
|
||||
a := sha512.Sum512(data)
|
||||
return a[0:64]
|
||||
}
|
||||
|
||||
func sumSHA3(data []byte) ([]byte, error) {
|
||||
h := sha3.New512()
|
||||
if _, err := h.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
66
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
Normal file
66
Godeps/_workspace/src/github.com/jbenet/go-multihash/sum_test.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SumTestCase struct {
|
||||
code int
|
||||
length int
|
||||
input string
|
||||
hex string
|
||||
}
|
||||
|
||||
var sumTestCases = []SumTestCase{
|
||||
SumTestCase{SHA1, -1, "foo", "11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"},
|
||||
SumTestCase{SHA1, 10, "foo", "110a0beec7b5ea3f0fdbc95d"},
|
||||
SumTestCase{SHA2_256, -1, "foo", "12202c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"},
|
||||
SumTestCase{SHA2_256, 16, "foo", "12102c26b46b68ffc68ff99b453c1d304134"},
|
||||
SumTestCase{SHA2_512, -1, "foo", "1340f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"},
|
||||
SumTestCase{SHA2_512, 32, "foo", "1320f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc663832"},
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
|
||||
for _, tc := range sumTestCases {
|
||||
|
||||
m1, err := FromHexString(tc.hex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
m2, err := Sum([]byte(tc.input), tc.code, tc.length)
|
||||
if err != nil {
|
||||
t.Error(tc.code, "sum failed.", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(m1, m2) {
|
||||
t.Error(tc.code, "sum failed.", m1, m2)
|
||||
}
|
||||
|
||||
s1 := m1.HexString()
|
||||
if s1 != tc.hex {
|
||||
t.Error("hex strings not the same")
|
||||
}
|
||||
|
||||
s2 := m1.B58String()
|
||||
m3, err := FromB58String(s2)
|
||||
if err != nil {
|
||||
t.Error("failed to decode b58")
|
||||
} else if !bytes.Equal(m3, m1) {
|
||||
t.Error("b58 failing bytes")
|
||||
} else if s2 != m3.B58String() {
|
||||
t.Error("b58 failing string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
tc := sumTestCases[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum([]byte(tc.input), tc.code, tc.length)
|
||||
}
|
||||
}
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/.gitignore
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
bin/multihash
|
||||
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/Makefile
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/Makefile
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
BINS = bin/multihash
|
||||
MULTIHASH_ROOT = ../
|
||||
MULTIHASH_CMD = ../multihash
|
||||
|
||||
all: deps
|
||||
|
||||
deps: bins
|
||||
|
||||
clean:
|
||||
rm $(BINS)
|
||||
|
||||
bins: $(BINS)
|
||||
|
||||
bin/multihash: $(MULTIHASH_ROOT)/**/*.go
|
||||
go build -o bin/multihash $(MULTIHASH_CMD)
|
||||
|
||||
test: test_expensive
|
||||
|
||||
test_expensive:
|
||||
cd sharness && make TEST_EXPENSIVE=1
|
||||
|
||||
test_cheap:
|
||||
cd sharness && make
|
||||
|
||||
.PHONY: all clean
|
||||
3
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/.gitignore
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
lib/sharness/
|
||||
test-results/
|
||||
trash directory.*.sh/
|
||||
37
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/Makefile
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/Makefile
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
# Run tests
|
||||
#
|
||||
# Copyright (c) 2014 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
# NOTE: run with TEST_VERBOSE=1 for verbose sharness tests.
|
||||
|
||||
T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
|
||||
BINS = bin/multihash
|
||||
SHARNESS = lib/sharness/sharness.sh
|
||||
|
||||
all: clean deps $(T) aggregate
|
||||
|
||||
clean:
|
||||
@echo "*** $@ ***"
|
||||
-rm -rf test-results
|
||||
|
||||
$(T):
|
||||
@echo "*** $@ ***"
|
||||
./$@
|
||||
|
||||
aggregate:
|
||||
@echo "*** $@ ***"
|
||||
lib/test-aggregate-results.sh
|
||||
|
||||
deps: $(SHARNESS) $(BINS)
|
||||
|
||||
$(SHARNESS):
|
||||
@echo "*** installing $@ ***"
|
||||
lib/install-sharness.sh
|
||||
|
||||
bin/%:
|
||||
@echo "*** installing $@ ***"
|
||||
cd .. && make $@
|
||||
|
||||
.PHONY: all clean $(T) aggregate
|
||||
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/bin
generated
vendored
Symbolic link
1
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/bin
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
../bin
|
||||
26
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/install-sharness.sh
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/install-sharness.sh
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
# install sharness.sh
|
||||
#
|
||||
# Copyright (c) 2014 Juan Batiz-Benet
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
# settings
|
||||
version=50229a79ba22b2f13ccd82451d86570fecbd194c
|
||||
urlprefix=https://github.com/mlafeldt/sharness.git
|
||||
clonedir=lib
|
||||
sharnessdir=sharness
|
||||
|
||||
die() {
|
||||
echo >&2 "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$clonedir" || die "Could not create '$clonedir' directory"
|
||||
cd "$clonedir" || die "Could not cd into '$clonedir' directory"
|
||||
|
||||
git clone "$urlprefix" || die "Could not clone '$urlprefix'"
|
||||
cd "$sharnessdir" || die "Could not cd into '$sharnessdir' directory"
|
||||
git checkout "$version" || die "Could not checkout '$version'"
|
||||
|
||||
exit 0
|
||||
17
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/test-aggregate-results.sh
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/test-aggregate-results.sh
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to aggregate results using Sharness
|
||||
#
|
||||
# Copyright (c) 2014 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
SHARNESS_AGGREGATE="lib/sharness/aggregate-results.sh"
|
||||
|
||||
test -f "$SHARNESS_AGGREGATE" || {
|
||||
echo >&2 "Cannot find: $SHARNESS_AGGREGATE"
|
||||
echo >&2 "Please check Sharness installation."
|
||||
exit 1
|
||||
}
|
||||
|
||||
ls test-results/t*-*.sh.*.counts | "$SHARNESS_AGGREGATE"
|
||||
43
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/test-lib.sh
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/lib/test-lib.sh
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# Test framework for go-ipfs
|
||||
#
|
||||
# Copyright (c) 2014 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
# We are using sharness (https://github.com/mlafeldt/sharness)
|
||||
# which was extracted from the Git test framework.
|
||||
|
||||
# Use the multihash tool to test against
|
||||
|
||||
# Add current directory to path, for multihash tool.
|
||||
PATH=$(pwd)/bin:${PATH}
|
||||
|
||||
# Set sharness verbosity. we set the env var directly as
|
||||
# it's too late to pass in --verbose, and --verbose is harder
|
||||
# to pass through in some cases.
|
||||
test "$TEST_VERBOSE" = 1 && verbose=t
|
||||
|
||||
# assert the `multihash` we're using is the right one.
|
||||
if test `which multihash` != $(pwd)/bin/multihash; then
|
||||
echo >&2 "Cannot find the tests' local multihash tool."
|
||||
echo >&2 "Please check test and multihash tool installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SHARNESS_LIB="lib/sharness/sharness.sh"
|
||||
|
||||
. "$SHARNESS_LIB" || {
|
||||
echo >&2 "Cannot source: $SHARNESS_LIB"
|
||||
echo >&2 "Please check Sharness installation."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Please put go-multihash specific shell functions below
|
||||
|
||||
for hashbin in sha1sum shasum; do
|
||||
if type "$hashbin"; then
|
||||
export SHASUMBIN="$hashbin" &&
|
||||
test_set_prereq SHASUM &&
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/t0010-basics.sh
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/t0010-basics.sh
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2015 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
test_description="Basic tests"
|
||||
|
||||
. lib/test-lib.sh
|
||||
|
||||
test_expect_success "current dir is writable" '
|
||||
echo "It works!" >test.txt
|
||||
'
|
||||
|
||||
test_expect_success "multihash is available" '
|
||||
type multihash
|
||||
'
|
||||
|
||||
test_expect_success "multihash help output looks good" '
|
||||
test_must_fail multihash -h 2>help.txt &&
|
||||
cat help.txt | egrep -i "^usage:" >/dev/null &&
|
||||
cat help.txt | egrep -i "multihash .*options.*file" >/dev/null
|
||||
'
|
||||
|
||||
test_done
|
||||
31
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/t0020-sha1.sh
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/jbenet/go-multihash/test/sharness/t0020-sha1.sh
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2015 Christian Couder
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
test_description="sha1 tests"
|
||||
|
||||
. lib/test-lib.sh
|
||||
|
||||
test_expect_success "setup sha1 tests" '
|
||||
echo "Hash me!" >hash_me.txt &&
|
||||
SHA1=bc6f2c3cd945bc754789e50b2f68deee2f421810 &&
|
||||
echo "1114$SHA1" >actual
|
||||
'
|
||||
|
||||
test_expect_success "'multihash -a=sha1 -e=hex' works" '
|
||||
multihash -a=sha1 -e=hex hash_me.txt >expected
|
||||
'
|
||||
|
||||
test_expect_success "'multihash -a=sha1 -e=hex' output looks good" '
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success SHASUM "check hash using shasum" '
|
||||
echo "$SHA1 hash_me.txt" >actual &&
|
||||
$SHASUMBIN hash_me.txt >expected &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_done
|
||||
66
Godeps/_workspace/src/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
66
Godeps/_workspace/src/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// Package sha3 implements the SHA-3 fixed-output-length hash functions and
|
||||
// the SHAKE variable-output-length hash functions defined by FIPS-202.
|
||||
//
|
||||
// Both types of hash function use the "sponge" construction and the Keccak
|
||||
// permutation. For a detailed specification see http://keccak.noekeon.org/
|
||||
//
|
||||
//
|
||||
// Guidance
|
||||
//
|
||||
// If you aren't sure what function you need, use SHAKE256 with at least 64
|
||||
// bytes of output. The SHAKE instances are faster than the SHA3 instances;
|
||||
// the latter have to allocate memory to conform to the hash.Hash interface.
|
||||
//
|
||||
// If you need a secret-key MAC (message authentication code), prepend the
|
||||
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
|
||||
// output.
|
||||
//
|
||||
//
|
||||
// Security strengths
|
||||
//
|
||||
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
|
||||
// strength against preimage attacks of x bits. Since they only produce "x"
|
||||
// bits of output, their collision-resistance is only "x/2" bits.
|
||||
//
|
||||
// The SHAKE-256 and -128 functions have a generic security strength of 256 and
|
||||
// 128 bits against all attacks, provided that at least 2x bits of their output
|
||||
// is used. Requesting more than 64 or 32 bytes of output, respectively, does
|
||||
// not increase the collision-resistance of the SHAKE functions.
|
||||
//
|
||||
//
|
||||
// The sponge construction
|
||||
//
|
||||
// A sponge builds a pseudo-random function from a public pseudo-random
|
||||
// permutation, by applying the permutation to a state of "rate + capacity"
|
||||
// bytes, but hiding "capacity" of the bytes.
|
||||
//
|
||||
// A sponge starts out with a zero state. To hash an input using a sponge, up
|
||||
// to "rate" bytes of the input are XORed into the sponge's state. The sponge
|
||||
// is then "full" and the permutation is applied to "empty" it. This process is
|
||||
// repeated until all the input has been "absorbed". The input is then padded.
|
||||
// The digest is "squeezed" from the sponge in the same way, except that output
|
||||
// output is copied out instead of input being XORed in.
|
||||
//
|
||||
// A sponge is parameterized by its generic security strength, which is equal
|
||||
// to half its capacity; capacity + rate is equal to the permutation's width.
|
||||
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
|
||||
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
|
||||
//
|
||||
//
|
||||
// Recommendations
|
||||
//
|
||||
// The SHAKE functions are recommended for most new uses. They can produce
|
||||
// output of arbitrary length. SHAKE256, with an output length of at least
|
||||
// 64 bytes, provides 256-bit security against all attacks. The Keccak team
|
||||
// recommends it for most applications upgrading from SHA2-512. (NIST chose a
|
||||
// much stronger, but much slower, sponge instance for SHA3-512.)
|
||||
//
|
||||
// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
|
||||
// They produce output of the same length, with the same security strengths
|
||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||
package sha3
|
||||
65
Godeps/_workspace/src/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
65
Godeps/_workspace/src/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sha3
|
||||
|
||||
// This file provides functions for creating instances of the SHA-3
|
||||
// and SHAKE hash functions, as well as utility functions for hashing
|
||||
// bytes.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
)
|
||||
|
||||
// New224 creates a new SHA3-224 hash.
|
||||
// Its generic security strength is 224 bits against preimage attacks,
|
||||
// and 112 bits against collision attacks.
|
||||
func New224() hash.Hash { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} }
|
||||
|
||||
// New256 creates a new SHA3-256 hash.
|
||||
// Its generic security strength is 256 bits against preimage attacks,
|
||||
// and 128 bits against collision attacks.
|
||||
func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} }
|
||||
|
||||
// New384 creates a new SHA3-384 hash.
|
||||
// Its generic security strength is 384 bits against preimage attacks,
|
||||
// and 192 bits against collision attacks.
|
||||
func New384() hash.Hash { return &state{rate: 104, outputLen: 48, dsbyte: 0x06} }
|
||||
|
||||
// New512 creates a new SHA3-512 hash.
|
||||
// Its generic security strength is 512 bits against preimage attacks,
|
||||
// and 256 bits against collision attacks.
|
||||
func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} }
|
||||
|
||||
// Sum224 returns the SHA3-224 digest of the data.
|
||||
func Sum224(data []byte) (digest [28]byte) {
|
||||
h := New224()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA3-256 digest of the data.
|
||||
func Sum256(data []byte) (digest [32]byte) {
|
||||
h := New256()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum384 returns the SHA3-384 digest of the data.
|
||||
func Sum384(data []byte) (digest [48]byte) {
|
||||
h := New384()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum512 returns the SHA3-512 digest of the data.
|
||||
func Sum512(data []byte) (digest [64]byte) {
|
||||
h := New512()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
410
Godeps/_workspace/src/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
410
Godeps/_workspace/src/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
@ -0,0 +1,410 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sha3
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
var rc = [24]uint64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
}
|
||||
|
||||
// keccakF1600 applies the Keccak permutation to a 1600b-wide
|
||||
// state represented as a slice of 25 uint64s.
|
||||
func keccakF1600(a *[25]uint64) {
|
||||
// Implementation translated from Keccak-inplace.c
|
||||
// in the keccak reference code.
|
||||
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
|
||||
|
||||
for i := 0; i < 24; i += 4 {
|
||||
// Combines the 5 steps in each round into 2 steps.
|
||||
// Unrolls 4 rounds per loop and spreads some steps across rounds.
|
||||
|
||||
// Round 1
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[6] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[12] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[18] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[24] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[16] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[22] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[3] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[1] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[7] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[19] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[11] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[23] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[4] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[2] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[8] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[14] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 2
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[16] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[7] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[23] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[14] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[11] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[2] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[18] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[6] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[22] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[4] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[1] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[8] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[24] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[12] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[3] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[19] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 3
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[11] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[22] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[8] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[19] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[1] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[12] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[23] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[16] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[2] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[24] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[6] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[3] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[14] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[7] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[18] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[4] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 4
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[1] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[2] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[3] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[4] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[6] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[7] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[8] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[11] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[12] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[14] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[16] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[18] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[19] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[22] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[23] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[24] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
}
|
||||
}
|
||||
18
Godeps/_workspace/src/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
18
Godeps/_workspace/src/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2014 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 go1.4
|
||||
|
||||
package sha3
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||
}
|
||||
193
Godeps/_workspace/src/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
193
Godeps/_workspace/src/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sha3
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
const (
|
||||
// spongeAbsorbing indicates that the sponge is absorbing input.
|
||||
spongeAbsorbing spongeDirection = iota
|
||||
// spongeSqueezing indicates that the sponge is being squeezed.
|
||||
spongeSqueezing
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRate is the maximum size of the internal buffer. SHAKE-256
|
||||
// currently needs the largest buffer.
|
||||
maxRate = 168
|
||||
)
|
||||
|
||||
type state struct {
|
||||
// Generic sponge components.
|
||||
a [25]uint64 // main state of the hash
|
||||
buf []byte // points into storage
|
||||
rate int // the number of bytes of state to use
|
||||
|
||||
// dsbyte contains the "domain separation" bits and the first bit of
|
||||
// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
|
||||
// SHA-3 and SHAKE functions by appending bitstrings to the message.
|
||||
// Using a little-endian bit-ordering convention, these are "01" for SHA-3
|
||||
// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
|
||||
// padding rule from section 5.1 is applied to pad the message to a multiple
|
||||
// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
|
||||
// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
|
||||
// giving 00000110b (0x06) and 00011111b (0x1f).
|
||||
// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
|
||||
// "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
|
||||
// Extendable-Output Functions (May 2014)"
|
||||
dsbyte byte
|
||||
storage [maxRate]byte
|
||||
|
||||
// Specific to SHA-3 and SHAKE.
|
||||
fixedOutput bool // whether this is a fixed-ouput-length instance
|
||||
outputLen int // the default output size in bytes
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
// BlockSize returns the rate of sponge underlying this hash function.
|
||||
func (d *state) BlockSize() int { return d.rate }
|
||||
|
||||
// Size returns the output size of the hash function in bytes.
|
||||
func (d *state) Size() int { return d.outputLen }
|
||||
|
||||
// Reset clears the internal state by zeroing the sponge state and
|
||||
// the byte buffer, and setting Sponge.state to absorbing.
|
||||
func (d *state) Reset() {
|
||||
// Zero the permutation's state.
|
||||
for i := range d.a {
|
||||
d.a[i] = 0
|
||||
}
|
||||
d.state = spongeAbsorbing
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
|
||||
func (d *state) clone() *state {
|
||||
ret := *d
|
||||
if ret.state == spongeAbsorbing {
|
||||
ret.buf = ret.storage[:len(ret.buf)]
|
||||
} else {
|
||||
ret.buf = ret.storage[d.rate-cap(d.buf) : d.rate]
|
||||
}
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
// permute applies the KeccakF-1600 permutation. It handles
|
||||
// any input-output buffering.
|
||||
func (d *state) permute() {
|
||||
switch d.state {
|
||||
case spongeAbsorbing:
|
||||
// If we're absorbing, we need to xor the input into the state
|
||||
// before applying the permutation.
|
||||
xorIn(d, d.buf)
|
||||
d.buf = d.storage[:0]
|
||||
keccakF1600(&d.a)
|
||||
case spongeSqueezing:
|
||||
// If we're squeezing, we need to apply the permutatin before
|
||||
// copying more output.
|
||||
keccakF1600(&d.a)
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
}
|
||||
|
||||
// pads appends the domain separation bits in dsbyte, applies
|
||||
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
||||
func (d *state) padAndPermute(dsbyte byte) {
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
// Pad with this instance's domain-separator bits. We know that there's
|
||||
// at least one byte of space in d.buf because, if it were full,
|
||||
// permute would have been called to empty it. dsbyte also contains the
|
||||
// first one bit for the padding. See the comment in the state struct.
|
||||
d.buf = append(d.buf, dsbyte)
|
||||
zerosStart := len(d.buf)
|
||||
d.buf = d.storage[:d.rate]
|
||||
for i := zerosStart; i < d.rate; i++ {
|
||||
d.buf[i] = 0
|
||||
}
|
||||
// This adds the final one bit for the padding. Because of the way that
|
||||
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
||||
// the last byte.
|
||||
d.buf[d.rate-1] ^= 0x80
|
||||
// Apply the permutation
|
||||
d.permute()
|
||||
d.state = spongeSqueezing
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
|
||||
// Write absorbs more data into the hash's state. It produces an error
|
||||
// if more data is written to the ShakeHash after writing
|
||||
func (d *state) Write(p []byte) (written int, err error) {
|
||||
if d.state != spongeAbsorbing {
|
||||
panic("sha3: write to sponge after read")
|
||||
}
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
written = len(p)
|
||||
|
||||
for len(p) > 0 {
|
||||
if len(d.buf) == 0 && len(p) >= d.rate {
|
||||
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
|
||||
xorIn(d, p[:d.rate])
|
||||
p = p[d.rate:]
|
||||
keccakF1600(&d.a)
|
||||
} else {
|
||||
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
||||
todo := d.rate - len(d.buf)
|
||||
if todo > len(p) {
|
||||
todo = len(p)
|
||||
}
|
||||
d.buf = append(d.buf, p[:todo]...)
|
||||
p = p[todo:]
|
||||
|
||||
// If the sponge is full, apply the permutation.
|
||||
if len(d.buf) == d.rate {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (d *state) Read(out []byte) (n int, err error) {
|
||||
// If we're still absorbing, pad and apply the permutation.
|
||||
if d.state == spongeAbsorbing {
|
||||
d.padAndPermute(d.dsbyte)
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// Now, do the squeezing.
|
||||
for len(out) > 0 {
|
||||
n := copy(out, d.buf)
|
||||
d.buf = d.buf[n:]
|
||||
out = out[n:]
|
||||
|
||||
// Apply the permutation if we've squeezed the sponge dry.
|
||||
if len(d.buf) == 0 {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired
|
||||
// number of output bytes.
|
||||
func (d *state) Sum(in []byte) []byte {
|
||||
// Make a copy of the original hash so that caller can keep writing
|
||||
// and summing.
|
||||
dup := d.clone()
|
||||
hash := make([]byte, dup.outputLen)
|
||||
dup.Read(hash)
|
||||
return append(in, hash...)
|
||||
}
|
||||
306
Godeps/_workspace/src/golang.org/x/crypto/sha3/sha3_test.go
generated
vendored
Normal file
306
Godeps/_workspace/src/golang.org/x/crypto/sha3/sha3_test.go
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sha3
|
||||
|
||||
// Tests include all the ShortMsgKATs provided by the Keccak team at
|
||||
// https://github.com/gvanas/KeccakCodePackage
|
||||
//
|
||||
// They only include the zero-bit case of the bitwise testvectors
|
||||
// published by NIST in the draft of FIPS-202.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"hash"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
testString = "brekeccakkeccak koax koax"
|
||||
katFilename = "testdata/keccakKats.json.deflate"
|
||||
)
|
||||
|
||||
// Internal-use instances of SHAKE used to test against KATs.
|
||||
func newHashShake128() hash.Hash {
|
||||
return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
|
||||
}
|
||||
func newHashShake256() hash.Hash {
|
||||
return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
|
||||
}
|
||||
|
||||
// testDigests contains functions returning hash.Hash instances
|
||||
// with output-length equal to the KAT length for both SHA-3 and
|
||||
// SHAKE instances.
|
||||
var testDigests = map[string]func() hash.Hash{
|
||||
"SHA3-224": New224,
|
||||
"SHA3-256": New256,
|
||||
"SHA3-384": New384,
|
||||
"SHA3-512": New512,
|
||||
"SHAKE128": newHashShake128,
|
||||
"SHAKE256": newHashShake256,
|
||||
}
|
||||
|
||||
// testShakes contains functions that return ShakeHash instances for
|
||||
// testing the ShakeHash-specific interface.
|
||||
var testShakes = map[string]func() ShakeHash{
|
||||
"SHAKE128": NewShake128,
|
||||
"SHAKE256": NewShake256,
|
||||
}
|
||||
|
||||
// decodeHex converts a hex-encoded string into a raw byte string.
|
||||
func decodeHex(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// structs used to marshal JSON test-cases.
|
||||
type KeccakKats struct {
|
||||
Kats map[string][]struct {
|
||||
Digest string `json:"digest"`
|
||||
Length int64 `json:"length"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
}
|
||||
|
||||
func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
|
||||
xorInOrig, copyOutOrig := xorIn, copyOut
|
||||
xorIn, copyOut = xorInGeneric, copyOutGeneric
|
||||
testf("generic")
|
||||
if xorImplementationUnaligned != "generic" {
|
||||
xorIn, copyOut = xorInUnaligned, copyOutUnaligned
|
||||
testf("unaligned")
|
||||
}
|
||||
xorIn, copyOut = xorInOrig, copyOutOrig
|
||||
}
|
||||
|
||||
// TestKeccakKats tests the SHA-3 and Shake implementations against all the
|
||||
// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
|
||||
// (The testvectors are stored in keccakKats.json.deflate due to their length.)
|
||||
func TestKeccakKats(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
// Read the KATs.
|
||||
deflated, err := os.Open(katFilename)
|
||||
if err != nil {
|
||||
t.Errorf("error opening %s: %s", katFilename, err)
|
||||
}
|
||||
file := flate.NewReader(deflated)
|
||||
dec := json.NewDecoder(file)
|
||||
var katSet KeccakKats
|
||||
err = dec.Decode(&katSet)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding KATs: %s", err)
|
||||
}
|
||||
|
||||
// Do the KATs.
|
||||
for functionName, kats := range katSet.Kats {
|
||||
d := testDigests[functionName]()
|
||||
for _, kat := range kats {
|
||||
d.Reset()
|
||||
in, err := hex.DecodeString(kat.Message)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding KAT: %s", err)
|
||||
}
|
||||
d.Write(in[:kat.Length/8])
|
||||
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
|
||||
if got != kat.Digest {
|
||||
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
|
||||
functionName, impl, kat.Length, kat.Message, got, kat.Digest)
|
||||
t.Logf("wanted %+v", kat)
|
||||
t.FailNow()
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestUnalignedWrite tests that writing data in an arbitrary pattern with
|
||||
// small input buffers.
|
||||
func testUnalignedWrite(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
buf := sequentialBytes(0x10000)
|
||||
for alg, df := range testDigests {
|
||||
d := df()
|
||||
d.Reset()
|
||||
d.Write(buf)
|
||||
want := d.Sum(nil)
|
||||
d.Reset()
|
||||
for i := 0; i < len(buf); {
|
||||
// Cycle through offsets which make a 137 byte sequence.
|
||||
// Because 137 is prime this sequence should exercise all corner cases.
|
||||
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
|
||||
for _, j := range offsets {
|
||||
if v := len(buf) - i; v < j {
|
||||
j = v
|
||||
}
|
||||
d.Write(buf[i : i+j])
|
||||
i += j
|
||||
}
|
||||
}
|
||||
got := d.Sum(nil)
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestAppend checks that appending works when reallocation is necessary.
|
||||
func TestAppend(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
d := New224()
|
||||
|
||||
for capacity := 2; capacity < 64; capacity += 64 {
|
||||
// The first time around the loop, Sum will have to reallocate.
|
||||
// The second time, it will not.
|
||||
buf := make([]byte, 2, capacity)
|
||||
d.Reset()
|
||||
d.Write([]byte{0xcc})
|
||||
buf = d.Sum(buf)
|
||||
expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
||||
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
||||
t.Errorf("got %s, want %s", got, expected)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
|
||||
func TestAppendNoRealloc(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
buf := make([]byte, 1, 200)
|
||||
d := New224()
|
||||
d.Write([]byte{0xcc})
|
||||
buf = d.Sum(buf)
|
||||
expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
||||
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
||||
t.Errorf("%s: got %s, want %s", impl, got, expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestSqueezing checks that squeezing the full output a single time produces
|
||||
// the same output as repeatedly squeezing the instance.
|
||||
func TestSqueezing(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
for functionName, newShakeHash := range testShakes {
|
||||
d0 := newShakeHash()
|
||||
d0.Write([]byte(testString))
|
||||
ref := make([]byte, 32)
|
||||
d0.Read(ref)
|
||||
|
||||
d1 := newShakeHash()
|
||||
d1.Write([]byte(testString))
|
||||
var multiple []byte
|
||||
for _ = range ref {
|
||||
one := make([]byte, 1)
|
||||
d1.Read(one)
|
||||
multiple = append(multiple, one...)
|
||||
}
|
||||
if !bytes.Equal(ref, multiple) {
|
||||
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
|
||||
func sequentialBytes(size int) []byte {
|
||||
result := make([]byte, size)
|
||||
for i := range result {
|
||||
result[i] = byte(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BenchmarkPermutationFunction measures the speed of the permutation function
|
||||
// with no input data.
|
||||
func BenchmarkPermutationFunction(b *testing.B) {
|
||||
b.SetBytes(int64(200))
|
||||
var lanes [25]uint64
|
||||
for i := 0; i < b.N; i++ {
|
||||
keccakF1600(&lanes)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkHash tests the speed to hash num buffers of buflen each.
|
||||
func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
|
||||
b.StopTimer()
|
||||
h.Reset()
|
||||
data := sequentialBytes(size)
|
||||
b.SetBytes(int64(size * num))
|
||||
b.StartTimer()
|
||||
|
||||
var state []byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < num; j++ {
|
||||
h.Write(data)
|
||||
}
|
||||
state = h.Sum(state[:0])
|
||||
}
|
||||
b.StopTimer()
|
||||
h.Reset()
|
||||
}
|
||||
|
||||
// benchmarkShake is specialized to the Shake instances, which don't
|
||||
// require a copy on reading output.
|
||||
func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
|
||||
b.StopTimer()
|
||||
h.Reset()
|
||||
data := sequentialBytes(size)
|
||||
d := make([]byte, 32)
|
||||
|
||||
b.SetBytes(int64(size * num))
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
h.Reset()
|
||||
for j := 0; j < num; j++ {
|
||||
h.Write(data)
|
||||
}
|
||||
h.Read(d)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
|
||||
func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
|
||||
func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
|
||||
func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
|
||||
|
||||
func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) }
|
||||
func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) }
|
||||
func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
|
||||
func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
|
||||
|
||||
func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
|
||||
|
||||
func Example_sum() {
|
||||
buf := []byte("some data to hash")
|
||||
// A hash needs to be 64 bytes long to have 256-bit collision resistance.
|
||||
h := make([]byte, 64)
|
||||
// Compute a 64-byte hash of buf and put it in h.
|
||||
ShakeSum256(h, buf)
|
||||
}
|
||||
|
||||
func Example_mac() {
|
||||
k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
|
||||
buf := []byte("and this is some data to authenticate")
|
||||
// A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
|
||||
h := make([]byte, 32)
|
||||
d := NewShake256()
|
||||
// Write the key into the hash.
|
||||
d.Write(k)
|
||||
// Now write the data.
|
||||
d.Write(buf)
|
||||
// Read 32 bytes of output from the hash into h.
|
||||
d.Read(h)
|
||||
}
|
||||
60
Godeps/_workspace/src/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
60
Godeps/_workspace/src/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sha3
|
||||
|
||||
// This file defines the ShakeHash interface, and provides
|
||||
// functions for creating SHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// ShakeHash defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
type ShakeHash interface {
|
||||
// Write absorbs more data into the hash's state. It panics if input is
|
||||
// written to it after output has been read from it.
|
||||
io.Writer
|
||||
|
||||
// Read reads more output from the hash; reading affects the hash's
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
||||
// It never returns an error.
|
||||
io.Reader
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
Clone() ShakeHash
|
||||
|
||||
// Reset resets the ShakeHash to its initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
func (d *state) Clone() ShakeHash {
|
||||
return d.clone()
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() ShakeHash { return &state{rate: 168, dsbyte: 0x1f} }
|
||||
|
||||
// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() ShakeHash { return &state{rate: 136, dsbyte: 0x1f} }
|
||||
|
||||
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum128(hash, data []byte) {
|
||||
h := NewShake128()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
|
||||
// ShakeSum256 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum256(hash, data []byte) {
|
||||
h := NewShake256()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
BIN
Godeps/_workspace/src/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
generated
vendored
Normal file
BIN
Godeps/_workspace/src/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
generated
vendored
Normal file
Binary file not shown.
16
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
16
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2015 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 !amd64,!386 appengine
|
||||
|
||||
package sha3
|
||||
|
||||
var (
|
||||
xorIn = xorInGeneric
|
||||
copyOut = copyOutGeneric
|
||||
xorInUnaligned = xorInGeneric
|
||||
copyOutUnaligned = copyOutGeneric
|
||||
)
|
||||
|
||||
const xorImplementationUnaligned = "generic"
|
||||
28
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor_generic.go
generated
vendored
Normal file
28
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor_generic.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
package sha3
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// xorInGeneric xors the bytes in buf into the state; it
|
||||
// makes no non-portable assumptions about memory layout
|
||||
// or alignment.
|
||||
func xorInGeneric(d *state, buf []byte) {
|
||||
n := len(buf) / 8
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
a := binary.LittleEndian.Uint64(buf)
|
||||
d.a[i] ^= a
|
||||
buf = buf[8:]
|
||||
}
|
||||
}
|
||||
|
||||
// copyOutGeneric copies ulint64s to a byte buffer.
|
||||
func copyOutGeneric(d *state, b []byte) {
|
||||
for i := 0; len(b) >= 8; i++ {
|
||||
binary.LittleEndian.PutUint64(b, d.a[i])
|
||||
b = b[8:]
|
||||
}
|
||||
}
|
||||
58
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor_unaligned.go
generated
vendored
Normal file
58
Godeps/_workspace/src/golang.org/x/crypto/sha3/xor_unaligned.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2015 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 amd64 386
|
||||
// +build !appengine
|
||||
|
||||
package sha3
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func xorInUnaligned(d *state, buf []byte) {
|
||||
bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))
|
||||
n := len(buf)
|
||||
if n >= 72 {
|
||||
d.a[0] ^= bw[0]
|
||||
d.a[1] ^= bw[1]
|
||||
d.a[2] ^= bw[2]
|
||||
d.a[3] ^= bw[3]
|
||||
d.a[4] ^= bw[4]
|
||||
d.a[5] ^= bw[5]
|
||||
d.a[6] ^= bw[6]
|
||||
d.a[7] ^= bw[7]
|
||||
d.a[8] ^= bw[8]
|
||||
}
|
||||
if n >= 104 {
|
||||
d.a[9] ^= bw[9]
|
||||
d.a[10] ^= bw[10]
|
||||
d.a[11] ^= bw[11]
|
||||
d.a[12] ^= bw[12]
|
||||
}
|
||||
if n >= 136 {
|
||||
d.a[13] ^= bw[13]
|
||||
d.a[14] ^= bw[14]
|
||||
d.a[15] ^= bw[15]
|
||||
d.a[16] ^= bw[16]
|
||||
}
|
||||
if n >= 144 {
|
||||
d.a[17] ^= bw[17]
|
||||
}
|
||||
if n >= 168 {
|
||||
d.a[18] ^= bw[18]
|
||||
d.a[19] ^= bw[19]
|
||||
d.a[20] ^= bw[20]
|
||||
}
|
||||
}
|
||||
|
||||
func copyOutUnaligned(d *state, buf []byte) {
|
||||
ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
|
||||
copy(buf, ab[:])
|
||||
}
|
||||
|
||||
var (
|
||||
xorIn = xorInUnaligned
|
||||
copyOut = copyOutUnaligned
|
||||
)
|
||||
|
||||
const xorImplementationUnaligned = "unaligned"
|
||||
@ -57,7 +57,7 @@ func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
|
||||
return ipm.Encapsulate(udpm), nil
|
||||
|
||||
case "utp", "utp4", "utp6":
|
||||
acc, ok := a.(*utp.UTPAddr)
|
||||
acc, ok := a.(*utp.Addr)
|
||||
if !ok {
|
||||
return nil, errIncorrectNetAddr
|
||||
}
|
||||
@ -117,7 +117,7 @@ func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
|
||||
case "udp", "udp4", "udp6":
|
||||
return net.ResolveUDPAddr(network, host)
|
||||
case "utp", "utp4", "utp6":
|
||||
return utp.ResolveUTPAddr(network, host)
|
||||
return utp.ResolveAddr(network, host)
|
||||
case "ip", "ip4", "ip6":
|
||||
return net.ResolveIPAddr(network, host)
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ func TestFromUDP(t *testing.T) {
|
||||
|
||||
func TestFromUTP(t *testing.T) {
|
||||
testConvert(t, "/ip4/10.20.30.40/udp/1234/utp", func() (ma.Multiaddr, error) {
|
||||
return FromNetAddr(&utp.UTPAddr{
|
||||
return FromNetAddr(&utp.Addr{
|
||||
Addr: &net.UDPAddr{
|
||||
IP: net.ParseIP("10.20.30.40"),
|
||||
Port: 1234,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user