mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-08 07:53:08 +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",
|
"ImportPath": "github.com/jbenet/go-multiaddr-net",
|
||||||
"GoVersion": "go1.3",
|
"GoVersion": "go1.4.2",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
],
|
],
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/h2so5/utp",
|
"ImportPath": "github.com/h2so5/utp",
|
||||||
"Rev": "654d875bb65e96729678180215cf080fe2810371"
|
"Rev": "5288a05e1781334589c4b8806bcfb1e69f5b5d63"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/jbenet/go-base58",
|
||||||
|
"Rev": "568a28d73fd97651d3442392036a658b6976eed5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/jbenet/go-multiaddr",
|
"ImportPath": "github.com/jbenet/go-multiaddr",
|
||||||
"Comment": "0.1.2-34-g0d7b54b",
|
"Comment": "0.1.2-38-gc13f11b",
|
||||||
"Rev": "0d7b54ba432fda14bac37cdad717bd6270eacc85"
|
"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
|
language: go
|
||||||
|
|
||||||
script:
|
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 test -v -race
|
||||||
- GO_UTP_LOGGING=2 go run benchmark/main.go -h
|
- 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
|
- 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
|
μTP (Micro Transport Protocol) implementation
|
||||||
|
|
||||||
[](https://ci.appveyor.com/project/h2so5/utp)
|
[](https://ci.appveyor.com/project/h2so5/utp)
|
||||||
[](https://travis-ci.org/h2so5/utp)
|
[](https://travis-ci.org/h2so5/utp)
|
||||||
[](http://godoc.org/github.com/h2so5/utp)
|
[](http://godoc.org/github.com/h2so5/utp)
|
||||||
|
|
||||||
http://www.bittorrent.org/beps/bep_0029.html
|
http://www.bittorrent.org/beps/bep_0029.html
|
||||||
|
|
||||||
**warning: This is a buggy alpha version.**
|
|
||||||
|
|
||||||
## Benchmark History
|
|
||||||
|
|
||||||
[]()
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```
|
```
|
||||||
go get github.com/h2so5/utp
|
go get github.com/h2so5/utp
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Debug Log
|
||||||
|
|
||||||
Echo server
|
Use GO_UTP_LOGGING to show debug logs.
|
||||||
|
|
||||||
```go
|
```
|
||||||
package main
|
GO_UTP_LOGGING=0 go test <- default, no logging
|
||||||
|
GO_UTP_LOGGING=1 go test
|
||||||
import (
|
GO_UTP_LOGGING=2 go test
|
||||||
"time"
|
GO_UTP_LOGGING=3 go test
|
||||||
|
GO_UTP_LOGGING=4 go test <- most verbose
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|||||||
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"
|
import "net"
|
||||||
|
|
||||||
type UTPAddr struct {
|
// Addr represents the address of a UTP end point.
|
||||||
|
type Addr struct {
|
||||||
net.Addr
|
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) {
|
func utp2udp(n string) (string, error) {
|
||||||
switch n {
|
switch n {
|
||||||
@ -20,15 +40,3 @@ func utp2udp(n string) (string, error) {
|
|||||||
return "", net.UnknownNetworkError(n)
|
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 {
|
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 {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
cch := make(chan *utp.Conn)
|
||||||
if err != nil {
|
go func() {
|
||||||
log.Fatal(err)
|
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 {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
cch <- c
|
||||||
defer c.Close()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := ln.Accept()
|
s, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,7 +114,11 @@ func c2s(l int64, stream bool) float64 {
|
|||||||
defer s.Close()
|
defer s.Close()
|
||||||
ln.Close()
|
ln.Close()
|
||||||
|
|
||||||
|
c := <-cch
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
rch := make(chan int)
|
rch := make(chan int)
|
||||||
|
wch := make(chan int)
|
||||||
|
|
||||||
sendHash := md5.New()
|
sendHash := md5.New()
|
||||||
readHash := md5.New()
|
readHash := md5.New()
|
||||||
@ -122,12 +128,13 @@ func c2s(l int64, stream bool) float64 {
|
|||||||
if stream {
|
if stream {
|
||||||
go func() {
|
go func() {
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
defer close(wch)
|
||||||
io.Copy(io.MultiWriter(c, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
io.Copy(io.MultiWriter(c, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(rch)
|
||||||
io.Copy(readHash, s)
|
io.Copy(readHash, s)
|
||||||
close(rch)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -148,6 +155,7 @@ func c2s(l int64, stream bool) float64 {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
<-rch
|
<-rch
|
||||||
|
<-wch
|
||||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -156,16 +164,18 @@ func c2s(l int64, stream bool) float64 {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
defer close(wch)
|
||||||
io.Copy(c, &sendBuf)
|
io.Copy(c, &sendBuf)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(rch)
|
||||||
io.Copy(&readBuf, s)
|
io.Copy(&readBuf, s)
|
||||||
rch <- 0
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
<-rch
|
<-rch
|
||||||
|
<-wch
|
||||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||||
|
|
||||||
io.Copy(sendHash, &sendBuf)
|
io.Copy(sendHash, &sendBuf)
|
||||||
@ -180,25 +190,27 @@ func c2s(l int64, stream bool) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func s2c(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 {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
cch := make(chan *utp.Conn)
|
||||||
if err != nil {
|
go func() {
|
||||||
log.Fatal(err)
|
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 {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
cch <- c
|
||||||
defer c.Close()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := ln.Accept()
|
s, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -207,7 +219,11 @@ func s2c(l int64, stream bool) float64 {
|
|||||||
defer s.Close()
|
defer s.Close()
|
||||||
ln.Close()
|
ln.Close()
|
||||||
|
|
||||||
|
c := <-cch
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
rch := make(chan int)
|
rch := make(chan int)
|
||||||
|
wch := make(chan int)
|
||||||
|
|
||||||
sendHash := md5.New()
|
sendHash := md5.New()
|
||||||
readHash := md5.New()
|
readHash := md5.New()
|
||||||
@ -218,12 +234,13 @@ func s2c(l int64, stream bool) float64 {
|
|||||||
if stream {
|
if stream {
|
||||||
go func() {
|
go func() {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
defer close(wch)
|
||||||
io.Copy(io.MultiWriter(s, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
io.Copy(io.MultiWriter(s, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(rch)
|
||||||
io.Copy(readHash, c)
|
io.Copy(readHash, c)
|
||||||
close(rch)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -244,6 +261,7 @@ func s2c(l int64, stream bool) float64 {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
<-rch
|
<-rch
|
||||||
|
<-wch
|
||||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -252,16 +270,18 @@ func s2c(l int64, stream bool) float64 {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
defer close(wch)
|
||||||
io.Copy(s, &sendBuf)
|
io.Copy(s, &sendBuf)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(rch)
|
||||||
io.Copy(&readBuf, c)
|
io.Copy(&readBuf, c)
|
||||||
rch <- 0
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
<-rch
|
<-rch
|
||||||
|
<-wch
|
||||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||||
|
|
||||||
io.Copy(sendHash, &sendBuf)
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"sync"
|
||||||
"time"
|
"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 {
|
if b.root == nil || b.root.p == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -157,6 +159,9 @@ func (b *packetBuffer) generateSelectiveACK() []byte {
|
|||||||
ack = ack[:len(ack)-1]
|
ack = ack[:len(ack)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(ack) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return ack
|
return ack
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,46 +190,280 @@ func (b *packetBuffer) processSelectiveACK(ack []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type timedBuffer struct {
|
type packetRingBuffer struct {
|
||||||
d time.Duration
|
b []*packet
|
||||||
root *timedBufferNode
|
begin int
|
||||||
|
s int
|
||||||
|
mutex sync.RWMutex
|
||||||
|
rch chan int
|
||||||
}
|
}
|
||||||
|
|
||||||
type timedBufferNode struct {
|
func newPacketRingBuffer(s int) *packetRingBuffer {
|
||||||
val float64
|
return &packetRingBuffer{
|
||||||
next *timedBufferNode
|
b: make([]*packet, s),
|
||||||
pushed time.Time
|
rch: make(chan int),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *timedBuffer) push(val float64) {
|
func (b *packetRingBuffer) size() int {
|
||||||
var before *timedBufferNode
|
b.mutex.RLock()
|
||||||
for n := b.root; n != nil; n = n.next {
|
defer b.mutex.RUnlock()
|
||||||
if time.Now().Sub(n.pushed) >= b.d {
|
return b.s
|
||||||
if before != nil {
|
}
|
||||||
before.next = nil
|
|
||||||
} else {
|
func (b *packetRingBuffer) empty() bool {
|
||||||
b.root = nil
|
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,
|
return len(b), nil
|
||||||
next: b.root,
|
}
|
||||||
pushed: time.Now(),
|
|
||||||
|
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 {
|
func (r *rateLimitedBuffer) Close() error {
|
||||||
if b.root == nil {
|
r.closechMutex.Lock()
|
||||||
return 0
|
defer r.closechMutex.Unlock()
|
||||||
|
select {
|
||||||
|
case <-r.closech:
|
||||||
|
return errClosing
|
||||||
|
default:
|
||||||
|
close(r.closech)
|
||||||
}
|
}
|
||||||
min := b.root.val
|
return nil
|
||||||
for n := b.root; n != nil; n = n.next {
|
}
|
||||||
if min > n.val {
|
|
||||||
min = n.val
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Dial(n, addr string) (*UTPConn, error) {
|
// DialUTP connects to the remote address raddr on the network net,
|
||||||
raddr, err := ResolveUTPAddr(n, addr)
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return DialUTP(n, nil, raddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DialUTP(n string, laddr, raddr *UTPAddr) (*UTPConn, error) {
|
id := uint16(rand.Intn(math.MaxUint16))
|
||||||
return dial(n, laddr, raddr, 0)
|
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) {
|
var t <-chan time.Time
|
||||||
return dial(n, laddr, raddr, timeout)
|
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.
|
// 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.
|
// Dial connects to the address on the named network.
|
||||||
//
|
//
|
||||||
// See func Dial for a description of the network and address parameters.
|
// See func Dial for a description of the network and address parameters.
|
||||||
func (d *Dialer) Dial(n, addr string) (*UTPConn, error) {
|
func (d *Dialer) Dial(n, addr string) (*Conn, error) {
|
||||||
raddr, err := ResolveUTPAddr(n, addr)
|
raddr, err := ResolveAddr(n, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var laddr *UTPAddr
|
var laddr *Addr
|
||||||
if d.LocalAddr != nil {
|
if d.LocalAddr != nil {
|
||||||
var ok bool
|
var ok bool
|
||||||
laddr, ok = d.LocalAddr.(*UTPAddr)
|
laddr, ok = d.LocalAddr.(*Addr)
|
||||||
if !ok {
|
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
|
package utp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"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.
|
// RawConn represents an out-of-band connection.
|
||||||
// This allows a single socket to handle multiple protocols.
|
// This allows a single socket to handle multiple protocols.
|
||||||
RawConn net.PacketConn
|
RawConn net.PacketConn
|
||||||
|
|
||||||
conn net.PacketConn
|
conn *baseConn
|
||||||
conns map[uint16]*UTPConn
|
deadline time.Time
|
||||||
accept chan (*UTPConn)
|
deadlineMutex sync.RWMutex
|
||||||
err chan (error)
|
closed int32
|
||||||
lasterr error
|
|
||||||
deadline time.Time
|
|
||||||
closech chan int
|
|
||||||
connch chan uint16
|
|
||||||
closed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Listen(n, laddr string) (*UTPListener, error) {
|
func (l *Listener) ok() bool { return l != nil && l.conn != nil }
|
||||||
addr, err := ResolveUTPAddr(n, laddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ListenUTP(n, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListenUTP(n string, laddr *UTPAddr) (*UTPListener, error) {
|
// Listen announces on the UTP address laddr and returns a UTP
|
||||||
udpnet, err := utp2udp(n)
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn, err := listenPacket(udpnet, laddr.Addr.String())
|
l := &Listener{
|
||||||
if err != nil {
|
RawConn: conn,
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l := UTPListener{
|
|
||||||
RawConn: newRawConn(conn),
|
|
||||||
conn: 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,
|
|
||||||
}
|
}
|
||||||
|
conn.Register(-1, nil)
|
||||||
l.listen()
|
return l, nil
|
||||||
return &l, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type incoming struct {
|
// Accept implements the Accept method in the Listener interface; it
|
||||||
p *packet
|
// waits for the next call and returns a generic Conn.
|
||||||
addr net.Addr
|
func (l *Listener) Accept() (net.Conn, error) {
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
return l.AcceptUTP()
|
return l.AcceptUTP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UTPListener) AcceptUTP() (*UTPConn, error) {
|
// AcceptUTP accepts the next incoming call and returns the new
|
||||||
if l == nil || l.conn == nil {
|
// connection.
|
||||||
|
func (l *Listener) AcceptUTP() (*Conn, error) {
|
||||||
|
if !l.ok() {
|
||||||
return nil, syscall.EINVAL
|
return nil, syscall.EINVAL
|
||||||
}
|
}
|
||||||
if l.lasterr != nil {
|
if !l.isOpen() {
|
||||||
return nil, l.lasterr
|
return nil, &net.OpError{
|
||||||
}
|
Op: "accept",
|
||||||
var timeout <-chan time.Time
|
Net: l.conn.LocalAddr().Network(),
|
||||||
if !l.deadline.IsZero() {
|
Addr: l.conn.LocalAddr(),
|
||||||
timeout = time.After(l.deadline.Sub(time.Now()))
|
Err: errClosing,
|
||||||
}
|
|
||||||
select {
|
|
||||||
case conn := <-l.accept:
|
|
||||||
if conn == nil {
|
|
||||||
return nil, errors.New("use of closed network connection")
|
|
||||||
}
|
}
|
||||||
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 {
|
// Addr returns the listener's network address, a *Addr.
|
||||||
return &UTPAddr{Addr: l.conn.LocalAddr()}
|
func (l *Listener) Addr() net.Addr {
|
||||||
|
if !l.ok() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return l.conn.LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UTPListener) Close() error {
|
// Close stops listening on the UTP address.
|
||||||
if l == nil || l.conn == nil {
|
// Already Accepted connections are not closed.
|
||||||
|
func (l *Listener) Close() error {
|
||||||
|
if !l.ok() {
|
||||||
return syscall.EINVAL
|
return syscall.EINVAL
|
||||||
}
|
}
|
||||||
l.closech <- 0
|
if !l.close() {
|
||||||
l.RawConn.Close()
|
return &net.OpError{
|
||||||
|
Op: "close",
|
||||||
|
Net: l.conn.LocalAddr().Network(),
|
||||||
|
Addr: l.conn.LocalAddr(),
|
||||||
|
Err: errClosing,
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UTPListener) SetDeadline(t time.Time) error {
|
// SetDeadline sets the deadline associated with the listener.
|
||||||
if l == nil || l.conn == nil {
|
// A zero time value disables the deadline.
|
||||||
|
func (l *Listener) SetDeadline(t time.Time) error {
|
||||||
|
if !l.ok() {
|
||||||
return syscall.EINVAL
|
return syscall.EINVAL
|
||||||
}
|
}
|
||||||
|
l.deadlineMutex.Lock()
|
||||||
|
defer l.deadlineMutex.Unlock()
|
||||||
l.deadline = t
|
l.deadline = t
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type rawIncoming struct {
|
func (l *Listener) close() bool {
|
||||||
b []byte
|
if atomic.CompareAndSwapInt32(&l.closed, 0, 1) {
|
||||||
addr net.Addr
|
l.conn.Unregister(-1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type rawConn struct {
|
func (l *Listener) isOpen() bool {
|
||||||
conn net.PacketConn
|
return atomic.LoadInt32(&l.closed) == 0
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
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"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type header struct {
|
type header struct {
|
||||||
@ -24,16 +25,11 @@ type packet struct {
|
|||||||
header header
|
header header
|
||||||
ext []extension
|
ext []extension
|
||||||
payload []byte
|
payload []byte
|
||||||
}
|
addr net.Addr
|
||||||
|
|
||||||
type outgoingPacket struct {
|
|
||||||
typ int
|
|
||||||
ext []extension
|
|
||||||
payload []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *packet) MarshalBinary() ([]byte, error) {
|
func (p *packet) MarshalBinary() ([]byte, error) {
|
||||||
firstExt := ext_none
|
firstExt := extNone
|
||||||
if len(p.ext) > 0 {
|
if len(p.ext) > 0 {
|
||||||
firstExt = p.ext[0].typ
|
firstExt = p.ext[0].typ
|
||||||
}
|
}
|
||||||
@ -68,7 +64,7 @@ func (p *packet) MarshalBinary() ([]byte, error) {
|
|||||||
|
|
||||||
if len(p.ext) > 0 {
|
if len(p.ext) > 0 {
|
||||||
for i, e := range p.ext {
|
for i, e := range p.ext {
|
||||||
next := ext_none
|
next := extNone
|
||||||
if i < len(p.ext)-1 {
|
if i < len(p.ext)-1 {
|
||||||
next = p.ext[i+1].typ
|
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)
|
currentExt := int(e)
|
||||||
var l uint8
|
var l uint8
|
||||||
var ext = []interface{}{
|
var ext = []interface{}{
|
||||||
@ -173,68 +169,30 @@ func (p *packet) UnmarshalBinary(data []byte) error {
|
|||||||
p.header.typ = int((tv >> 4) & 0xF)
|
p.header.typ = int((tv >> 4) & 0xF)
|
||||||
p.header.ver = int(tv & 0xF)
|
p.header.ver = int(tv & 0xF)
|
||||||
|
|
||||||
l := buf.Len()
|
data, err := ioutil.ReadAll(buf)
|
||||||
if l > 0 {
|
if err != nil {
|
||||||
p.payload = p.payload[:l]
|
return err
|
||||||
_, err := buf.Read(p.payload[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
p.payload = data
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p packet) String() string {
|
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 {
|
switch p.header.typ {
|
||||||
case st_data:
|
case stData:
|
||||||
s += "ST_DATA"
|
s += "ST_DATA"
|
||||||
case st_fin:
|
case stFin:
|
||||||
s += "ST_FIN"
|
s += "ST_FIN"
|
||||||
case st_state:
|
case stState:
|
||||||
s += "ST_STATE"
|
s += "ST_STATE"
|
||||||
case st_reset:
|
case stReset:
|
||||||
s += "ST_RESET"
|
s += "ST_RESET"
|
||||||
case st_syn:
|
case stSyn:
|
||||||
s += "ST_SYN"
|
s += "ST_SYN"
|
||||||
}
|
}
|
||||||
s += fmt.Sprintf(" seq:%d ack:%d len:%d", p.header.seq, p.header.ack, len(p.payload))
|
s += fmt.Sprintf(" seq:%d ack:%d len:%d", p.header.seq, p.header.ack, len(p.payload))
|
||||||
s += "]"
|
s += "]"
|
||||||
return 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,
|
// Listen listens and accepts one incoming uTP connection on a given port,
|
||||||
// and pipes all incoming data to os.Stdout.
|
// and pipes all incoming data to os.Stdout.
|
||||||
func Listen(localAddr string) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -138,7 +142,7 @@ func Dial(localAddr, remoteAddr string) error {
|
|||||||
var laddr net.Addr
|
var laddr net.Addr
|
||||||
var err error
|
var err error
|
||||||
if localAddr != "" {
|
if localAddr != "" {
|
||||||
laddr, err = utp.ResolveUTPAddr("utp", localAddr)
|
laddr, err = utp.ResolveAddr("utp", localAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to resolve address %s", localAddr)
|
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
|
package utp
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
st_data = 0
|
stData = 0
|
||||||
st_fin = 1
|
stFin = 1
|
||||||
st_state = 2
|
stState = 2
|
||||||
st_reset = 3
|
stReset = 3
|
||||||
st_syn = 4
|
stSyn = 4
|
||||||
|
|
||||||
ext_none = 0
|
stateClosed = iota
|
||||||
ext_selective_ack = 1
|
stateClosing
|
||||||
|
stateSynSent
|
||||||
|
stateConnected
|
||||||
|
stateFinSent
|
||||||
|
|
||||||
header_size = 20
|
extNone = 0
|
||||||
mtu = 3200
|
extSelectiveAck = 1
|
||||||
mss = mtu - header_size
|
|
||||||
window_size = 100
|
|
||||||
|
|
||||||
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{}
|
type timeoutError struct{}
|
||||||
@ -27,3 +40,8 @@ type timeoutError struct{}
|
|||||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||||
func (e *timeoutError) Timeout() bool { return true }
|
func (e *timeoutError) Timeout() bool { return true }
|
||||||
func (e *timeoutError) Temporary() 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
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.2
|
|
||||||
- 1.3
|
- 1.3
|
||||||
- release
|
- release
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
script:
|
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 (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
mh "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||||
)
|
)
|
||||||
|
|
||||||
func stringToBytes(s string) ([]byte, error) {
|
func stringToBytes(s string) ([]byte, error) {
|
||||||
@ -31,17 +34,19 @@ func stringToBytes(s string) ([]byte, error) {
|
|||||||
b = append(b, CodeToVarint(p.Code)...)
|
b = append(b, CodeToVarint(p.Code)...)
|
||||||
sp = sp[1:]
|
sp = sp[1:]
|
||||||
|
|
||||||
if p.Size > 0 {
|
if p.Size == 0 { // no length.
|
||||||
if len(sp) < 1 {
|
continue
|
||||||
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 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
|
return b, nil
|
||||||
}
|
}
|
||||||
@ -51,7 +56,14 @@ func bytesToString(b []byte) (ret string, err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
ret = ""
|
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 {
|
if p.Code == 0 {
|
||||||
return "", fmt.Errorf("no protocol with code %d", code)
|
return "", fmt.Errorf("no protocol with code %d", code)
|
||||||
}
|
}
|
||||||
s = strings.Join([]string{s, "/", p.Name}, "")
|
s += "/" + p.Name
|
||||||
|
|
||||||
if p.Size > 0 {
|
if p.Size == 0 {
|
||||||
a := addressBytesToString(p, b[:(p.Size/8)])
|
continue
|
||||||
if len(a) > 0 {
|
|
||||||
s = strings.Join([]string{s, "/", a}, "")
|
|
||||||
}
|
|
||||||
b = b[(p.Size / 8):]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
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) {
|
func bytesSplit(b []byte) (ret [][]byte, err error) {
|
||||||
// panic handler, in case we try accessing bytes incorrectly.
|
// panic handler, in case we try accessing bytes incorrectly.
|
||||||
defer func() {
|
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])
|
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])
|
ret = append(ret, b[:length])
|
||||||
b = b[length:]
|
b = b[length:]
|
||||||
}
|
}
|
||||||
@ -133,23 +164,46 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) {
|
|||||||
b := make([]byte, 2)
|
b := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(b, uint16(i))
|
binary.BigEndian.PutUint16(b, uint16(i))
|
||||||
return b, nil
|
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)
|
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 {
|
switch p.Code {
|
||||||
|
|
||||||
// ipv4,6
|
// ipv4,6
|
||||||
case P_IP4, P_IP6:
|
case P_IP4, P_IP6:
|
||||||
return net.IP(b).String()
|
return net.IP(b).String(), nil
|
||||||
|
|
||||||
// tcp udp dccp sctp
|
// tcp udp dccp sctp
|
||||||
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
||||||
i := binary.BigEndian.Uint16(b)
|
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{}
|
ps := []Protocol{}
|
||||||
b := m.bytes[:]
|
b := m.bytes[:]
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
@ -75,7 +76,10 @@ func (m *multiaddr) Protocols() []Protocol {
|
|||||||
panic(fmt.Errorf("no protocol with code %d", b[0]))
|
panic(fmt.Errorf("no protocol with code %d", b[0]))
|
||||||
}
|
}
|
||||||
ps = append(ps, p)
|
ps = append(ps, p)
|
||||||
b = b[n+(p.Size/8):]
|
b = b[n:]
|
||||||
|
|
||||||
|
size = sizeForAddr(p, b)
|
||||||
|
b = b[size:]
|
||||||
}
|
}
|
||||||
return ps
|
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/udp",
|
||||||
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
|
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
|
||||||
"/ip4/127.0.0.1/tcp",
|
"/ip4/127.0.0.1/tcp",
|
||||||
|
"/ip4/127.0.0.1/ipfs",
|
||||||
|
"/ip4/127.0.0.1/ipfs/tcp",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range cases {
|
for _, a := range cases {
|
||||||
if _, err := NewMultiaddr(a); err == nil {
|
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",
|
"/sctp/1234",
|
||||||
"/udp/65535",
|
"/udp/65535",
|
||||||
"/tcp/65535",
|
"/tcp/65535",
|
||||||
|
"/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
|
||||||
"/udp/1234/sctp/1234",
|
"/udp/1234/sctp/1234",
|
||||||
"/udp/1234/udt",
|
"/udp/1234/udt",
|
||||||
"/udp/1234/utp",
|
"/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/1234",
|
||||||
"/ip4/127.0.0.1/udp/0",
|
"/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/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 {
|
for _, a := range cases {
|
||||||
if _, err := NewMultiaddr(a); err != nil {
|
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
|
132 16 sctp
|
||||||
301 0 udt
|
301 0 udt
|
||||||
302 0 utp
|
302 0 utp
|
||||||
|
421 V ipfs
|
||||||
480 0 http
|
480 0 http
|
||||||
443 0 https
|
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.
|
// Protocol is a Multiaddr protocol description structure.
|
||||||
type Protocol struct {
|
type Protocol struct {
|
||||||
Code int
|
Code int
|
||||||
Size int
|
Size int // a size of -1 indicates a length-prefixed variable size
|
||||||
Name string
|
Name string
|
||||||
VCode []byte
|
VCode []byte
|
||||||
}
|
}
|
||||||
@ -19,14 +19,22 @@ type Protocol struct {
|
|||||||
// 2. ensuring errors in the csv don't screw up code.
|
// 2. ensuring errors in the csv don't screw up code.
|
||||||
// 3. changing a number has to happen in two places.
|
// 3. changing a number has to happen in two places.
|
||||||
const (
|
const (
|
||||||
P_IP4 = 4
|
P_IP4 = 4
|
||||||
P_TCP = 6
|
P_TCP = 6
|
||||||
P_UDP = 17
|
P_UDP = 17
|
||||||
P_DCCP = 33
|
P_DCCP = 33
|
||||||
P_IP6 = 41
|
P_IP6 = 41
|
||||||
P_SCTP = 132
|
P_SCTP = 132
|
||||||
P_UTP = 301
|
P_UTP = 301
|
||||||
P_UDT = 302
|
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.
|
// 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_SCTP, 16, "sctp", CodeToVarint(P_SCTP)},
|
||||||
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)},
|
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)},
|
||||||
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)},
|
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)},
|
||||||
// {480, 0, "http"},
|
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)},
|
||||||
// {443, 0, "https"},
|
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.
|
// 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
|
return ipm.Encapsulate(udpm), nil
|
||||||
|
|
||||||
case "utp", "utp4", "utp6":
|
case "utp", "utp4", "utp6":
|
||||||
acc, ok := a.(*utp.UTPAddr)
|
acc, ok := a.(*utp.Addr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errIncorrectNetAddr
|
return nil, errIncorrectNetAddr
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
|
|||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
return net.ResolveUDPAddr(network, host)
|
return net.ResolveUDPAddr(network, host)
|
||||||
case "utp", "utp4", "utp6":
|
case "utp", "utp4", "utp6":
|
||||||
return utp.ResolveUTPAddr(network, host)
|
return utp.ResolveAddr(network, host)
|
||||||
case "ip", "ip4", "ip6":
|
case "ip", "ip4", "ip6":
|
||||||
return net.ResolveIPAddr(network, host)
|
return net.ResolveIPAddr(network, host)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ func TestFromUDP(t *testing.T) {
|
|||||||
|
|
||||||
func TestFromUTP(t *testing.T) {
|
func TestFromUTP(t *testing.T) {
|
||||||
testConvert(t, "/ip4/10.20.30.40/udp/1234/utp", func() (ma.Multiaddr, error) {
|
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{
|
Addr: &net.UDPAddr{
|
||||||
IP: net.ParseIP("10.20.30.40"),
|
IP: net.ParseIP("10.20.30.40"),
|
||||||
Port: 1234,
|
Port: 1234,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user