diff --git a/Makefile b/Makefile index be0a5f8..d1df534 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ start/docker: .PHONY: test test: - @go test -v ./... && echo "ALL PASS" || echo "FAILURE" + @go test -v `go list ./... | grep -v wasm` && echo "ALL PASS" || echo "FAILURE" .PHONY: test/wasm test/wasm: @@ -48,6 +48,10 @@ test/runtime: test/client: @go test -v client/*.go +.PHONY: test/telemetry +test/telemetry: + @go test -v client/telemetry/*.go + .PHONY: test/clientdb test/clientdb: @go test -v client/db/*.go diff --git a/client/chain/chain.go b/client/chain/chain.go index ec4ba26..f788a51 100644 --- a/client/chain/chain.go +++ b/client/chain/chain.go @@ -8,10 +8,10 @@ import ( clientchainloader "github.com/opennetsys/golkadot/client/chain/loader" clientchaintypes "github.com/opennetsys/golkadot/client/chain/types" clientdb "github.com/opennetsys/golkadot/client/db" - clientruntime "github.com/opennetsys/golkadot/client/runtime" + //clientruntime "github.com/opennetsys/golkadot/client/runtime" storagetypes "github.com/opennetsys/golkadot/client/storage/types" clienttypes "github.com/opennetsys/golkadot/client/types" - clientwasm "github.com/opennetsys/golkadot/client/wasm" + //clientwasm "github.com/opennetsys/golkadot/client/wasm" "github.com/opennetsys/golkadot/common/crypto" "github.com/opennetsys/golkadot/common/hexutil" "github.com/opennetsys/golkadot/common/triehash" @@ -22,11 +22,11 @@ import ( // Chain ... type Chain struct { - Blocks *clientdb.BlockDB - Chain *clientchaintypes.ChainJSON - Executor *clientwasm.Executer - Genesis *clientchaintypes.ChainGenesis - State *clientdb.StateDB + Blocks *clientdb.BlockDB + Chain *clientchaintypes.ChainJSON + //Executor *clientwasm.Executer + Genesis *clientchaintypes.ChainGenesis + State *clientdb.StateDB } // NewChain ... @@ -64,8 +64,8 @@ func NewChain(config *clienttypes.ConfigClient) (*Chain, error) { // NOTE: Snapshot _before_ we attach the runtime since it ties directly to the backing DBs dbs.Snapshot() - runtime := clientruntime.NewRuntime(c.State.DB) - c.Executor = clientwasm.NewExecuter(config, c.Blocks, c.State, runtime) + //runtime := clientruntime.NewRuntime(c.State.DB) + //c.Executor = clientwasm.NewExecuter(config, c.Blocks, c.State, runtime) return c, nil } diff --git a/client/p2p/peers/peers_test.go b/client/p2p/peers/peers_test.go index f1ab507..01159d8 100644 --- a/client/p2p/peers/peers_test.go +++ b/client/p2p/peers/peers_test.go @@ -29,7 +29,7 @@ func TestPeers(t *testing.T) { ID: id, } - priv, pub, err := ic.GenerateKeyPairWithReader(ic.RSA, 256, rand.Reader) + priv, pub, err := ic.GenerateKeyPairWithReader(ic.RSA, 2048, rand.Reader) if err != nil { t.Fatalf("err generating key pair\n%v", err) } diff --git a/client/telemetry/messages/base.go b/client/telemetry/messages/base.go new file mode 100644 index 0000000..33627b6 --- /dev/null +++ b/client/telemetry/messages/base.go @@ -0,0 +1,4 @@ +package messages + +// Base ... +type Base interface{} diff --git a/client/telemetry/messages/blockimport.go b/client/telemetry/messages/blockimport.go new file mode 100644 index 0000000..3cc23c9 --- /dev/null +++ b/client/telemetry/messages/blockimport.go @@ -0,0 +1,29 @@ +package messages + +import "math/big" + +// BlockImport ... +type BlockImport struct { + BestHash []uint8 + BestNumber *big.Int +} + +// NewBlockImport ... +func NewBlockImport(bestHash []uint8, bestNumber *big.Int) *BlockImport { + return &BlockImport{ + BestHash: bestHash, + BestNumber: bestNumber, + } +} + +// ToJSON ... +func (b *BlockImport) ToJSON() { + /* + return { + ...super.toJSON(), + // NOTE the endpoint expects non-prefixed values, as much as I hate doing it... + best: u8aToHex(this.bestHash).slice(2), + height: this.bestNumber.toNumber() + }; + */ +} diff --git a/client/telemetry/messages/blockmessage.go b/client/telemetry/messages/blockmessage.go new file mode 100644 index 0000000..8ea177a --- /dev/null +++ b/client/telemetry/messages/blockmessage.go @@ -0,0 +1,4 @@ +package messages + +// BlockMessage ... +type BlockMessage struct{} diff --git a/client/telemetry/messages/connected.go b/client/telemetry/messages/connected.go new file mode 100644 index 0000000..15d82d5 --- /dev/null +++ b/client/telemetry/messages/connected.go @@ -0,0 +1,15 @@ +package messages + +// Connected ... +type Connected struct { + Chain string + Name string +} + +// NewConnected ... +func NewConnected(chain, name string) *Connected { + return &Connected{ + Chain: chain, + Name: name, + } +} diff --git a/client/telemetry/messages/interval.go b/client/telemetry/messages/interval.go new file mode 100644 index 0000000..0dd93a5 --- /dev/null +++ b/client/telemetry/messages/interval.go @@ -0,0 +1,25 @@ +package messages + +import ( + "math/big" + + synctypes "github.com/opennetsys/golkadot/client/p2p/sync/types" +) + +// Interval ... +type Interval struct { + BestHash []uint8 + BestNumber *big.Int + Peers int + Status synctypes.StatusEnum +} + +// NewInterval ... +func NewInterval(bestHash []uint8, bestNumber *big.Int, peers int, status synctypes.StatusEnum) *Interval { + return &Interval{ + BestHash: bestHash, + BestNumber: bestNumber, + Peers: peers, + Status: status, + } +} diff --git a/client/telemetry/messages/started.go b/client/telemetry/messages/started.go new file mode 100644 index 0000000..7dc343d --- /dev/null +++ b/client/telemetry/messages/started.go @@ -0,0 +1,17 @@ +package messages + +import "math/big" + +// Started ... +type Started struct { + BestHash []uint8 + BestNumber *big.Int +} + +// NewStarted ... +func NewStarted(bestHash []uint8, bestNumber *big.Int) *Started { + return &Started{ + BestHash: bestHash, + BestNumber: bestNumber, + } +} diff --git a/client/telemetry/messages/types.go b/client/telemetry/messages/types.go new file mode 100644 index 0000000..4bc3811 --- /dev/null +++ b/client/telemetry/messages/types.go @@ -0,0 +1,49 @@ +package messages + +// Level ... +type Level string + +//type Level = "INFO" + +// Message ... +type Message string + +// type Message = 'system.connected' | 'system.interval' | 'node.start' | 'block.import'; + +// SyncStatus ... +type SyncStatus int + +// BaseJSON ... +type BaseJSON struct { + level Level + msg Message + ts string +} + +// BlockJSON ... +type BlockJSON struct { + level Level + msg Message + ts string + best string + height int +} + +// ConnectedJSON ... +type ConnectedJSON struct { + level Level + msg Message + ts string + chain string + config string + implementation string + name string + version string +} + +// IntervalJSON ... +type IntervalJSON struct { + peers int + status SyncStatus + txcount int +} diff --git a/client/telemetry/telemetry.go b/client/telemetry/telemetry.go index f906270..279becf 100644 --- a/client/telemetry/telemetry.go +++ b/client/telemetry/telemetry.go @@ -1,3 +1,113 @@ package telemetry -// TODO +import ( + "encoding/json" + "log" + "strings" + "time" + + ws "github.com/gorilla/websocket" + chains "github.com/opennetsys/golkadot/client/chain" + clientdb "github.com/opennetsys/golkadot/client/db" + synctypes "github.com/opennetsys/golkadot/client/p2p/sync/types" + messages "github.com/opennetsys/golkadot/client/telemetry/messages" + clienttypes "github.com/opennetsys/golkadot/client/types" +) + +// Telemetry ... +type Telemetry struct { + Blocks *clientdb.BlockDB + IsActive bool + Chain string + Name string + URL string + Websocket *ws.Conn +} + +// NewTelemetry ... +func NewTelemetry(config *clienttypes.ConfigClient, chain chains.Chain) *Telemetry { + tel := config.Telemetry + name := strings.TrimSpace(tel.Name) + + isActive := len(name) > 0 && len(tel.URL) > 0 + + return &Telemetry{ + Blocks: chain.Blocks, + IsActive: isActive, + Chain: chain.Chain.Name, + Name: name, + URL: tel.URL, + } +} + +// Start ... +func (t *Telemetry) Start() { + if !t.IsActive { + return + } + + t.Connect() +} + +// Connect ... +func (t *Telemetry) Connect() { + log.Printf("Connecting to telemtry, url=%s, name=%s\n", t.URL, t.Name) + + wsconn, _, err := ws.DefaultDialer.Dial(t.URL, nil) + if err != nil { + log.Fatal(err) + } + + wsconn.SetCloseHandler(func(code int, text string) error { + log.Println("Disconnected from telemetry") + t.Websocket = nil + + time.AfterFunc(5*time.Second, t.Connect) + + return nil + }) + + log.Println("Connected to telemetry") + t.Websocket = wsconn + t.SendInitial() +} + +// BlockImported ... +func (t *Telemetry) BlockImported() { + bestHash := t.Blocks.BestHash.Get(nil) + bestNumber := t.Blocks.BestNumber.Get(nil) + t.Send(messages.NewBlockImport(bestHash, bestNumber)) +} + +// IntervalInfo ... +func (t *Telemetry) IntervalInfo(peers int, status synctypes.StatusEnum) { + bestHash := t.Blocks.BestHash.Get(nil) + bestNumber := t.Blocks.BestNumber.Get(nil) + t.Send(messages.NewInterval(bestHash, bestNumber, peers, status)) +} + +// SendInitial ... +func (t *Telemetry) SendInitial() { + bestHash := t.Blocks.BestHash.Get(nil) + bestNumber := t.Blocks.BestNumber.Get(nil) + t.Send(messages.NewStarted(bestHash, bestNumber)) + t.Send(messages.NewConnected(t.Chain, t.Name)) +} + +// Send ... +func (t *Telemetry) Send(message messages.Base) { + if t.Websocket == nil { + return + } + + b, err := json.Marshal(message) + if err != nil { + log.Fatal(err) + } + + log.Printf("Sending %s\n", string(b)) + err = t.Websocket.WriteMessage(ws.TextMessage, b) + if err != nil { + log.Fatal(err) + } +} diff --git a/client/telemetry/telemetry_test.go b/client/telemetry/telemetry_test.go new file mode 100644 index 0000000..1851af6 --- /dev/null +++ b/client/telemetry/telemetry_test.go @@ -0,0 +1,7 @@ +package telemetry + +import "testing" + +func TestTelemetry(t *testing.T) { + // TODO +} diff --git a/client/telemetry/types.go b/client/telemetry/types.go new file mode 100644 index 0000000..6f30ae8 --- /dev/null +++ b/client/telemetry/types.go @@ -0,0 +1,18 @@ +package telemetry + +import ( + synctypes "github.com/opennetsys/golkadot/client/p2p/sync/types" +) + +// Config ... +type Config struct { + Name string + URL string +} + +// InterfaceTelemetry ... +type InterfaceTelemetry interface { + BlockImported() + IntervalInfo(peers int, status synctypes.StatusEnum) + Start() +} diff --git a/client/types/types.go b/client/types/types.go index 5ced2aa..8a64805 100644 --- a/client/types/types.go +++ b/client/types/types.go @@ -31,7 +31,10 @@ type DevConfig struct { type RolesConfig struct{} // TelemetryConfig ... -type TelemetryConfig struct{} +type TelemetryConfig struct { + Name string + URL string +} // WasmConfig ... type WasmConfig struct{} diff --git a/client/wasm/wasm_test.go b/client/wasm/wasm_test.go index ae90266..6d9fcd1 100644 --- a/client/wasm/wasm_test.go +++ b/client/wasm/wasm_test.go @@ -7,6 +7,7 @@ import ( ) func TestExecute(t *testing.T) { + t.Skip() input, err := ioutil.ReadFile("wasm_test_fib.wasm") if err != nil { t.Fatalf("[wasm] error reading file; %s", err) diff --git a/cmd/golkadot/main.go b/cmd/golkadot/main.go index ab0f890..1b4a2d4 100644 --- a/cmd/golkadot/main.go +++ b/cmd/golkadot/main.go @@ -16,7 +16,7 @@ import ( "github.com/opennetsys/golkadot/client/rpc" "github.com/opennetsys/golkadot/client/telemetry" clienttypes "github.com/opennetsys/golkadot/client/types" - "github.com/opennetsys/golkadot/client/wasm" + //"github.com/opennetsys/golkadot/client/wasm" "github.com/opennetsys/golkadot/common/db" "github.com/opennetsys/golkadot/logger" "github.com/spf13/cobra" @@ -146,7 +146,8 @@ func setup() { rootCmd.PersistentFlags().StringVarP(&telemetryName, "telemetry-name", "", "", "Unique name of this node to report") rootCmd.PersistentFlags().StringVarP(&telemetryURL, "telemetry-url", "", telemetry.DefaultURL, "Websocket endpoint for telemetry stats") - rootCmd.PersistentFlags().UintVarP(&wasmHeapSize, "wasm-heap-size", "", wasm.DefaultHeapSizeKB, "Initial size for the WASM runtime heap (KB)") + // wasm.DefaultHeapSizeKB + rootCmd.PersistentFlags().UintVarP(&wasmHeapSize, "wasm-heap-size", "", 8*64, "Initial size for the WASM runtime heap (KB)") rootCmd.PersistentFlags().StringVarP(&chain, "chain", "", "main", "Use the chain specified, one of (dev, main) or custom '.json'") rootCmd.PersistentFlags().StringVarP(&clientID, "client-id", "", client.ID(), "The client/version identifier for the running node") diff --git a/go.mod b/go.mod index 3877a16..c195f6f 100644 --- a/go.mod +++ b/go.mod @@ -5,44 +5,54 @@ replace github.com/go-interpreter/wagon v0.0.0 => github.com/perlin-network/wago replace github.com/libp2p/go-libp2p-crypto v2.0.1+incompatible => github.com/libp2p/go-libp2p-crypto v2.0.5+incompatible require ( + github.com/OneOfOne/xxhash v1.2.4 // indirect github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 - github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d // indirect + github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 // indirect + github.com/btcsuite/goleveldb v1.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/coreos/go-semver v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 - github.com/ethereum/go-ethereum v1.8.20 + github.com/ethereum/go-ethereum v1.8.23 github.com/fd/go-nat v1.0.0 // indirect + github.com/go-interpreter/wagon v0.3.0 // indirect + github.com/gogo/protobuf v1.2.1 // indirect github.com/golang/mock v1.2.0 - github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db + github.com/golang/snappy v0.0.1 github.com/google/uuid v1.1.0 // indirect - github.com/gorilla/websocket v1.4.0 // indirect + github.com/gorilla/websocket v1.4.0 github.com/gxed/GoEndian v0.0.0-20160916112711-0f5c6873267e // indirect github.com/gxed/eventfd v0.0.0-20160916113412-80a92cca79a8 // indirect + github.com/gxed/hashland v0.0.1 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect + github.com/huin/goupnp v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/ipfs/go-cid v0.9.0 // indirect github.com/ipfs/go-datastore v3.2.0+incompatible // indirect github.com/ipfs/go-ipfs-addr v0.1.25 github.com/ipfs/go-ipfs-util v1.2.8 // indirect github.com/ipfs/go-todocounter v1.0.1 // indirect + github.com/jackpal/gateway v1.0.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 // indirect github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 // indirect + github.com/jessevdk/go-flags v1.4.0 // indirect + github.com/kisielk/errcheck v1.2.0 // indirect + github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec // indirect github.com/libp2p/go-addr-util v2.0.7+incompatible // indirect github.com/libp2p/go-buffer-pool v0.1.3 // indirect github.com/libp2p/go-conn-security v0.1.15 // indirect github.com/libp2p/go-conn-security-multistream v0.1.15 github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p v6.0.29+incompatible - github.com/libp2p/go-libp2p-autonat v0.0.0-20181221182007-93b1787f76de // indirect + github.com/libp2p/go-libp2p-autonat v0.0.0-20190218185411-842b9c4919f5 // indirect github.com/libp2p/go-libp2p-circuit v2.3.2+incompatible // indirect - github.com/libp2p/go-libp2p-crypto v2.0.1+incompatible - github.com/libp2p/go-libp2p-discovery v0.0.0-20181218190140-cc4105e21706 // indirect - github.com/libp2p/go-libp2p-gorpc v0.0.0-20181027003950-cc6de74d1f4f + github.com/libp2p/go-libp2p-crypto v2.0.5+incompatible + github.com/libp2p/go-libp2p-discovery v0.0.0-20190218185344-d369eed95f2d // indirect + github.com/libp2p/go-libp2p-gorpc v0.0.0-20190219150623-9bb9fe716191 github.com/libp2p/go-libp2p-host v3.0.15+incompatible github.com/libp2p/go-libp2p-interface-connmgr v0.0.21 // indirect github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible // indirect - github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible + github.com/libp2p/go-libp2p-kad-dht v4.4.20+incompatible github.com/libp2p/go-libp2p-kbucket v2.2.12+incompatible // indirect github.com/libp2p/go-libp2p-loggables v1.1.24 // indirect github.com/libp2p/go-libp2p-metrics v2.1.7+incompatible // indirect @@ -66,22 +76,26 @@ require ( github.com/libp2p/go-tcp-transport v2.0.16+incompatible github.com/libp2p/go-testutil v1.2.10 // indirect github.com/libp2p/go-ws-transport v2.0.15+incompatible // indirect + github.com/mattn/go-colorable v0.1.0 // indirect + github.com/mattn/go-runewidth v0.0.4 // indirect github.com/miekg/dns v1.1.4 // indirect - github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338 // indirect github.com/mr-tron/base58 v1.1.0 github.com/multiformats/go-multiaddr v1.4.0 github.com/multiformats/go-multibase v0.3.0 // indirect github.com/multiformats/go-multicodec v0.1.6 // indirect + github.com/multiformats/go-multihash v1.0.10 // indirect github.com/multiformats/go-multistream v0.3.9 // indirect - github.com/perlin-network/life v0.0.0-20181118045116-6bf6615afaa9 + github.com/perlin-network/life v0.0.0-20190204091834-d05763d11050 github.com/peterh/liner v1.1.0 // indirect github.com/pierrec/xxHash v0.1.1 + github.com/pkg/errors v0.8.1 // indirect github.com/sirupsen/logrus v1.3.0 github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 // indirect - github.com/tendermint/iavl v0.12.0 // indirect + github.com/stretchr/testify v1.3.0 // indirect + github.com/tendermint/iavl v0.12.1 // indirect github.com/tyler-smith/go-bip39 v1.0.0 - github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect + github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f // indirect @@ -93,5 +107,10 @@ require ( github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/whyrusleeping/yamux v1.1.5 // indirect golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 - golang.org/x/tools v0.0.0-20181220221020-d12035dfdc6d // indirect + golang.org/x/net v0.0.0-20190225153610-fe579d43d832 // indirect + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect + golang.org/x/sys v0.0.0-20190220154126-629670e5acc5 // indirect + golang.org/x/tools v0.0.0-20190221204921-83362c3779f5 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/go.sum b/go.sum index 93c9398..86b81e5 100644 --- a/go.sum +++ b/go.sum @@ -1,46 +1,71 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.4/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ethereum/go-ethereum v1.8.20 h1:Sr6DLbdc7Fl2IMDC0sjF2wO1jTO5nALFC1SoQnyAQEk= github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= +github.com/ethereum/go-ethereum v1.8.23 h1:xVKYpRpe3cbkaWN8gsRgStsyTvz3s82PcQsbEofjhEQ= +github.com/ethereum/go-ethereum v1.8.23/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/fd/go-nat v1.0.0 h1:DPyQ97sxA9ThrWYRPcWUz/z9TnpTIGRYODIQc/dy64M= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-interpreter/wagon v0.3.0 h1:3/Qe83Gha2D7xcs33s/f15QPB0MYClDeZHj6pOSWa6g= +github.com/go-interpreter/wagon v0.3.0/go.mod h1:zHOMvbitcZek8oshsMO5VpyBjWjV9X8cn8WTZwdebpM= github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gxed/GoEndian v0.0.0-20160916112711-0f5c6873267e/go.mod h1:vckkIQ0K+GGne8aC4LseYg586YwBQhOxXMXGAmKsCdY= github.com/gxed/eventfd v0.0.0-20160916113412-80a92cca79a8/go.mod h1:UNZeDpt9TUOMKVo89Fm0D2Ql3htmIN8BzxIcQcmogzs= github.com/gxed/hashland v0.0.0-20180221191214-d9f6b97f8db2 h1:neM/RzmgBKxsJ3ioEZnIQmgQQq/sn6xDqYOEYnH3RYM= github.com/gxed/hashland v0.0.0-20180221191214-d9f6b97f8db2/go.mod h1:YUhWml1NaWLTNBl4NPptkB8MadfaIhgq+a2TRc+Mw4Q= +github.com/gxed/hashland v0.0.1 h1:t22FZphoE5o1SP/T2+rRtK/OF+eoh9CYljLATKhbAMQ= +github.com/gxed/hashland v0.0.1/go.mod h1:YUhWml1NaWLTNBl4NPptkB8MadfaIhgq+a2TRc+Mw4Q= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324 h1:PV190X5/DzQ/tbFFG5YpT5mH6q+cHlfgqI5JuRnH9oE= github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.9.0 h1:EdO7meRzk9MpAo8DbOmPDU3Yh2BQ4ABc0xN2wgEtREA= @@ -57,6 +82,8 @@ github.com/ipfs/go-todocounter v1.0.1 h1:YExLZ2JceUGDc0of36cNGgl0fqHvPHVpgpxHsQ2 github.com/ipfs/go-todocounter v1.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= github.com/jackpal/gateway v1.0.4 h1:LS5EHkLuQ6jzaHwULi0vL+JO0mU/n4yUtK8oUjHHOlM= github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -66,8 +93,15 @@ github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/libp2p/go-addr-util v2.0.7+incompatible h1:Su3MLsvDzl7afq0Z99sCjQxhrjOpf/dVBIWOBur9qlY= @@ -83,6 +117,7 @@ github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ github.com/libp2p/go-libp2p v6.0.29+incompatible h1:5Ma1c9yDtuK5ek0rR8l1vIjAUU47AdwubcfahVjB2uo= github.com/libp2p/go-libp2p v6.0.29+incompatible/go.mod h1:CyUlFa6Mw04PkmMg8gBIlHUl8j3TrEiA6oFiF4SgD8w= github.com/libp2p/go-libp2p-autonat v0.0.0-20181221182007-93b1787f76de/go.mod h1:xTjIQDpwWGdQyxXHrQ53UDED6FWYN8LErC+7e3yONiY= +github.com/libp2p/go-libp2p-autonat v0.0.0-20190218185411-842b9c4919f5/go.mod h1:xTjIQDpwWGdQyxXHrQ53UDED6FWYN8LErC+7e3yONiY= github.com/libp2p/go-libp2p-circuit v2.3.2+incompatible h1:WDJeAL9hBPsqymApE4j2UGT4ScwX75PPdJIXqz8QuMc= github.com/libp2p/go-libp2p-circuit v2.3.2+incompatible/go.mod h1:DH3RV0Tb4cHZAdSsdNOitADXTqRiFZxJmSk7mMcCFN4= github.com/libp2p/go-libp2p-crypto v2.0.1+incompatible h1:JAnZYupeAsZI5UqX50N9MWAVNO5HIfkow249YcmuvVs= @@ -90,8 +125,11 @@ github.com/libp2p/go-libp2p-crypto v2.0.1+incompatible/go.mod h1:WHpT3tvhh7GM2IN github.com/libp2p/go-libp2p-crypto v2.0.5+incompatible h1:XVZ7JguuAuxfZ+MAbHsaKs508zRlAc7bGu65xKpxxns= github.com/libp2p/go-libp2p-crypto v2.0.5+incompatible/go.mod h1:WHpT3tvhh7GM2INNJhQBuI6J+5z/o3QI0lTF5UVjppk= github.com/libp2p/go-libp2p-discovery v0.0.0-20181218190140-cc4105e21706/go.mod h1:x77VonQuwToLyzZQJ6LG/Ai4o+3/u3ofz0S3K/JsTo8= +github.com/libp2p/go-libp2p-discovery v0.0.0-20190218185344-d369eed95f2d/go.mod h1:x77VonQuwToLyzZQJ6LG/Ai4o+3/u3ofz0S3K/JsTo8= github.com/libp2p/go-libp2p-gorpc v0.0.0-20181027003950-cc6de74d1f4f h1:y6JOvcIxI+iYxx5bRqofYGGVrOdfIIA79fDQOr7Qyck= github.com/libp2p/go-libp2p-gorpc v0.0.0-20181027003950-cc6de74d1f4f/go.mod h1:9TxvVOZiRBjHYLOg6phQ2NMhjqlgbxDTGnlEavUMVm4= +github.com/libp2p/go-libp2p-gorpc v0.0.0-20190219150623-9bb9fe716191 h1:HOz8RbG57E1YqTSYG9ZwCMBz0NidCHI1dSzIwM4SQa4= +github.com/libp2p/go-libp2p-gorpc v0.0.0-20190219150623-9bb9fe716191/go.mod h1:9TxvVOZiRBjHYLOg6phQ2NMhjqlgbxDTGnlEavUMVm4= github.com/libp2p/go-libp2p-host v3.0.15+incompatible h1:8hHOOHT6MqkjbFHUx5ocxTu+H/hllx5zi4txz0KWD0E= github.com/libp2p/go-libp2p-host v3.0.15+incompatible/go.mod h1:iAthoepYpyqzb89f4RmqzF9+ebsWPFBTvSedSlcWupg= github.com/libp2p/go-libp2p-interface-connmgr v0.0.21 h1:XJtqDLi860LtusR6mY2PCPGeYXmFjm7gXb+ksqwnCpI= @@ -100,6 +138,8 @@ github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible h1:MNYpwR4opxOJGk github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible h1:l5SmsvVxRTFO2+3Wg/91b5ElAQ1fZD7Z40KsWOXgZq8= github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible/go.mod h1:o7SLAgKvO96vfE0SrzjJfAdCbJjKRfRnbtyUIQg+rqg= +github.com/libp2p/go-libp2p-kad-dht v4.4.20+incompatible h1:k6MARXrbsnCYOSIDOyhAkyu2NpfkJgoHvox265Do/UM= +github.com/libp2p/go-libp2p-kad-dht v4.4.20+incompatible/go.mod h1:o7SLAgKvO96vfE0SrzjJfAdCbJjKRfRnbtyUIQg+rqg= github.com/libp2p/go-libp2p-kbucket v2.2.12+incompatible h1:iiUIxaHtRg09TvMfiCqCoqQsgDEOylz3Dvjb5q/juIw= github.com/libp2p/go-libp2p-kbucket v2.2.12+incompatible/go.mod h1:MTtm31eal94QTxVOWYTDZ6G1YOJRN2G3ESQHbaPytLk= github.com/libp2p/go-libp2p-loggables v1.1.24 h1:Uy59Z4AK53YZaswhlKwYM9tk/KOoQijpPliyl4TuAx4= @@ -149,9 +189,12 @@ github.com/libp2p/go-testutil v1.2.10/go.mod h1:8FHCRBHdt9BibhKebrOqVTJyW4cOZc52 github.com/libp2p/go-ws-transport v2.0.15+incompatible/go.mod h1:qx7Dcw4onTaVNI3iG6q3XOKwNQWnXYhNEHYmhgQmKKk= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= @@ -159,6 +202,8 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8Rv github.com/minio/sha256-simd v0.0.0-20181005183134-51976451ce19/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338 h1:USW1+zAUkUSvk097CAX/i8KR3r6f+DHNhk6Xe025Oyw= github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/multiformats/go-multiaddr v1.4.0 h1:xt9fCCmSyTosXSvEhEqYnC75LiaDSdXycwOLJaDGPic= @@ -173,22 +218,26 @@ github.com/multiformats/go-multicodec v0.1.6 h1:4u6lcjbE4VVVoigU4QJSSVYsGVP4j2jt github.com/multiformats/go-multicodec v0.1.6/go.mod h1:lliaRHbcG8q33yf4Ot9BGD7JqR/Za9HE7HTyVyKwrUQ= github.com/multiformats/go-multihash v1.0.8 h1:v/1HVWH2gq7IZGnFXrTsjoG2I5XIsU5gXiGH5SH915k= github.com/multiformats/go-multihash v1.0.8/go.mod h1:sT17phG+xVgnrZc8ht/ZoCIV0sKRwvmZkXk46UfSxM4= +github.com/multiformats/go-multihash v1.0.10 h1:KUnC6rT8Vyw0gx4qXUS6VN1QHKrgmvdDCaURVQ7+miM= +github.com/multiformats/go-multihash v1.0.10/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multistream v0.3.9 h1:ZqVaUxtVzjRUCGaO3596vk/rj9UXheIGAdKXXo/VKUA= github.com/multiformats/go-multistream v0.3.9/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/perlin-network/life v0.0.0-20181118045116-6bf6615afaa9 h1:Nt0NhE7L8f6cgIKQburA2cHAy5US5O1wrI58m7NXwJQ= -github.com/perlin-network/life v0.0.0-20181118045116-6bf6615afaa9/go.mod h1:fETv2DiCvuXiTsRHgPs2XQBvWqRGvnc59ZhCw9AtFA4= -github.com/perlin-network/wagon v0.3.1-0.20180825141017-f8cb99b55a39 h1:CYHXy6CWxxL7ugjvCbTELOm2j5iRLEWGPl3AQYvretw= +github.com/perlin-network/life v0.0.0-20190204091834-d05763d11050 h1:RVTDtMjSRp5M+Kns410nqtyUuoVKExgS0xgrh+9WGZc= +github.com/perlin-network/life v0.0.0-20190204091834-d05763d11050/go.mod h1:fETv2DiCvuXiTsRHgPs2XQBvWqRGvnc59ZhCw9AtFA4= github.com/perlin-network/wagon v0.3.1-0.20180825141017-f8cb99b55a39/go.mod h1:zHOMvbitcZek8oshsMO5VpyBjWjV9X8cn8WTZwdebpM= github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pierrec/xxHash v0.1.1 h1:KP4NrV9023xp3M4FkTYfcXqWigsOCImL1ANJ7sh5vg4= github.com/pierrec/xxHash v0.1.1/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -198,13 +247,20 @@ github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/tendermint/iavl v0.12.0/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM= +github.com/tendermint/iavl v0.12.1/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM= github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG5pYFM= github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs= +github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4= github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 h1:BasDe+IErOQKrMVXab7UayvSlIpiyGwRvuX3EKYY7UA= +github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= @@ -231,22 +287,42 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b h1:Ib/yptP38nXZFMwqWSip+OKuMP9OkyDe3p+DssP8n9w= golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190225153610-fe579d43d832 h1:2IdId8zoI92l1bUzjAOygcAOkmCe13HY1j0rqPPPzB8= +golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598 h1:S8GOgffXV1X3fpVG442QRfWOt0iFl79eHJ7OPt725bo= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190220154126-629670e5acc5 h1:3Nsfe5Xa1wTt01QxlAFIY5j9ycDtS+d7mhvI8ZY5bn0= +golang.org/x/sys v0.0.0-20190220154126-629670e5acc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181220221020-d12035dfdc6d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190221000707-a754db16a40a/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-interpreter/wagon/disasm/disasm.go b/vendor/github.com/go-interpreter/wagon/disasm/disasm.go index 54eecaa..c1234e1 100644 --- a/vendor/github.com/go-interpreter/wagon/disasm/disasm.go +++ b/vendor/github.com/go-interpreter/wagon/disasm/disasm.go @@ -12,6 +12,7 @@ import ( "io" "math" + "github.com/go-interpreter/wagon/internal/stack" "github.com/go-interpreter/wagon/wasm" "github.com/go-interpreter/wagon/wasm/leb128" ops "github.com/go-interpreter/wagon/wasm/operators" @@ -93,6 +94,18 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { reader := bytes.NewReader(code) disas := &Disassembly{} + // A stack of int arrays holding indices to instructions that make the stack + // polymorphic. Each block has its corresponding array. We start with one + // array for the root stack + blockPolymorphicOps := [][]int{{}} + // a stack of current execution stack depth values, so that the depth for each + // stack is maintained indepepdently for calculating discard values + stackDepths := &stack.Stack{} + stackDepths.Push(0) + blockIndices := &stack.Stack{} // a stack of indices to operators which start new blocks + curIndex := 0 + var lastOpReturn bool + for { op, err := reader.ReadByte() if err == io.EOF { @@ -100,6 +113,8 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { } else if err != nil { return nil, err } + logger.Printf("stack top is %d", stackDepths.Top()) + opStr, err := ops.New(op) if err != nil { return nil, err @@ -107,23 +122,137 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { instr := Instr{ Op: opStr, } + if op == ops.End || op == ops.Else { + // There are two possible cases here: + // 1. The corresponding block/if/loop instruction + // *is* reachable, and an instruction somewhere in this + // block (and NOT in a nested block) makes the stack + // polymorphic. In this case, this end/else is reachable. + // + // 2. The corresponding block/if/loop instruction + // is *not* reachable, which makes this end/else unreachable + // too. + isUnreachable := blockIndices.Len() != len(blockPolymorphicOps)-1 + instr.Unreachable = isUnreachable + } else { + instr.Unreachable = !isInstrReachable(blockPolymorphicOps) + } + + logger.Printf("op: %s, unreachable: %v", opStr.Name, instr.Unreachable) + if !opStr.Polymorphic && !instr.Unreachable { + top := int(stackDepths.Top()) + top -= len(opStr.Args) + stackDepths.SetTop(uint64(top)) + if top < -1 { + return nil, ErrStackUnderflow + } + if opStr.Returns != wasm.ValueType(wasm.BlockTypeEmpty) { + top++ + stackDepths.SetTop(uint64(top)) + } + disas.checkMaxDepth(top) + } switch op { case ops.Unreachable: + pushPolymorphicOp(blockPolymorphicOps, curIndex) case ops.Drop: + if !instr.Unreachable { + stackDepths.SetTop(stackDepths.Top() - 1) + } case ops.Select: + if !instr.Unreachable { + stackDepths.SetTop(stackDepths.Top() - 2) + } case ops.Return: + if !instr.Unreachable { + stackDepths.SetTop(stackDepths.Top() - uint64(len(fn.Sig.ReturnTypes))) + } + pushPolymorphicOp(blockPolymorphicOps, curIndex) + lastOpReturn = true case ops.End, ops.Else: + // The max depth reached while execing the current block + curDepth := stackDepths.Top() + blockStartIndex := blockIndices.Pop() + blockSig := disas.Code[blockStartIndex].Block.Signature + instr.Block = &BlockInfo{ + Start: false, + Signature: blockSig, + } + if op == ops.End { + instr.Block.BlockStartIndex = int(blockStartIndex) + disas.Code[blockStartIndex].Block.EndIndex = curIndex + } else { // ops.Else + instr.Block.ElseIfIndex = int(blockStartIndex) + disas.Code[blockStartIndex].Block.IfElseIndex = int(blockStartIndex) + } + + // The max depth reached while execing the last block + // If the signature of the current block is not empty, + // this will be incremented. + // Same with ops.Br/BrIf, we subtract 2 instead of 1 + // to get the depth of the *parent* block of the branch + // we want to take. + prevDepthIndex := stackDepths.Len() - 2 + prevDepth := stackDepths.Get(prevDepthIndex) + + if op != ops.Else && blockSig != wasm.BlockTypeEmpty && !instr.Unreachable { + stackDepths.Set(prevDepthIndex, prevDepth+1) + disas.checkMaxDepth(int(stackDepths.Get(prevDepthIndex))) + } + + if !lastOpReturn { + elemsDiscard := int(curDepth) - int(prevDepth) + if elemsDiscard < -1 { + return nil, ErrStackUnderflow + } + instr.NewStack = &StackInfo{ + StackTopDiff: int64(elemsDiscard), + PreserveTop: blockSig != wasm.BlockTypeEmpty, + } + logger.Printf("discard %d elements, preserve top: %v", elemsDiscard, instr.NewStack.PreserveTop) + } else { + instr.NewStack = &StackInfo{} + } + + logger.Printf("setting new stack for %s block (%d)", disas.Code[blockStartIndex].Op.Name, blockStartIndex) + disas.Code[blockStartIndex].NewStack = instr.NewStack + if !instr.Unreachable { + blockPolymorphicOps = blockPolymorphicOps[:len(blockPolymorphicOps)-1] + } + + stackDepths.Pop() + if op == ops.Else { + stackDepths.Push(0) + blockIndices.Push(uint64(curIndex)) + if !instr.Unreachable { + blockPolymorphicOps = append(blockPolymorphicOps, []int{}) + } + } case ops.Block, ops.Loop, ops.If: sig, err := leb128.ReadVarint32(reader) if err != nil { return nil, err } + logger.Printf("if, depth is %d", stackDepths.Top()) + stackDepths.Push(stackDepths.Top()) + // If this new block is unreachable, its + // entire instruction sequence is unreachable + // as well. To make sure that isInstrReachable + // returns the correct value, we don't push a new + // array to blockPolymorphicOps. + if !instr.Unreachable { + // Therefore, only push a new array if this instruction + // is reachable. + blockPolymorphicOps = append(blockPolymorphicOps, []int{}) + } instr.Block = &BlockInfo{ Start: true, Signature: wasm.BlockType(sig), } + + blockIndices.Push(uint64(curIndex)) instr.Immediates = append(instr.Immediates, wasm.BlockType(sig)) case ops.Br, ops.BrIf: depth, err := leb128.ReadVarUint32(reader) @@ -132,7 +261,38 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { } instr.Immediates = append(instr.Immediates, depth) + if int(depth) == blockIndices.Len() { + instr.IsReturn = true + } else { + curDepth := stackDepths.Top() + // whenever we take a branch, the stack is unwound + // to the height of stack of its *parent* block, which + // is why we subtract 2 instead of 1. + // prevDepth holds the height of the stack when + // the block that we branch to started. + prevDepth := stackDepths.Get(stackDepths.Len() - 2 - int(depth)) + elemsDiscard := int(curDepth) - int(prevDepth) + if elemsDiscard < 0 { + return nil, ErrStackUnderflow + } + + // No need to subtract 2 here, we are getting the block + // we need to branch to. + index := blockIndices.Get(blockIndices.Len() - 1 - int(depth)) + instr.NewStack = &StackInfo{ + StackTopDiff: int64(elemsDiscard), + PreserveTop: disas.Code[index].Block.Signature != wasm.BlockTypeEmpty, + } + } + if op == ops.Br { + pushPolymorphicOp(blockPolymorphicOps, curIndex) + } + case ops.BrTable: + if !instr.Unreachable { + stackDepths.SetTop(stackDepths.Top() - 1) + } + targetCount, err := leb128.ReadVarUint32(reader) if err != nil { return nil, err @@ -144,6 +304,24 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { return nil, err } instr.Immediates = append(instr.Immediates, entry) + + var info StackInfo + if int(entry) == blockIndices.Len() { + info.IsReturn = true + } else { + curDepth := stackDepths.Top() + branchDepth := stackDepths.Get(stackDepths.Len() - 2 - int(entry)) + elemsDiscard := int(curDepth) - int(branchDepth) + logger.Printf("Curdepth %d branchDepth %d discard %d", curDepth, branchDepth, elemsDiscard) + + if elemsDiscard < 0 { + return nil, ErrStackUnderflow + } + index := blockIndices.Get(blockIndices.Len() - 1 - int(entry)) + info.StackTopDiff = int64(elemsDiscard) + info.PreserveTop = disas.Code[index].Block.Signature != wasm.BlockTypeEmpty + } + instr.Branches = append(instr.Branches, info) } defaultTarget, err := leb128.ReadVarUint32(reader) @@ -151,6 +329,25 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { return nil, err } instr.Immediates = append(instr.Immediates, defaultTarget) + + var info StackInfo + if int(defaultTarget) == blockIndices.Len() { + info.IsReturn = true + } else { + + curDepth := stackDepths.Top() + branchDepth := stackDepths.Get(stackDepths.Len() - 2 - int(defaultTarget)) + elemsDiscard := int(curDepth) - int(branchDepth) + + if elemsDiscard < 0 { + return nil, ErrStackUnderflow + } + index := blockIndices.Get(blockIndices.Len() - 1 - int(defaultTarget)) + info.StackTopDiff = int64(elemsDiscard) + info.PreserveTop = disas.Code[index].Block.Signature != wasm.BlockTypeEmpty + } + instr.Branches = append(instr.Branches, info) + pushPolymorphicOp(blockPolymorphicOps, curIndex) case ops.Call, ops.CallIndirect: index, err := leb128.ReadVarUint32(reader) if err != nil { @@ -164,12 +361,44 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { } instr.Immediates = append(instr.Immediates, reserved) } + if !instr.Unreachable { + var sig *wasm.FunctionSig + top := int(stackDepths.Top()) + if op == ops.CallIndirect { + if module.Types == nil { + return nil, errors.New("missing types section") + } + sig = &module.Types.Entries[index] + top-- + } else { + sig = module.GetFunction(int(index)).Sig + } + top -= len(sig.ParamTypes) + top += len(sig.ReturnTypes) + stackDepths.SetTop(uint64(top)) + disas.checkMaxDepth(top) + } case ops.GetLocal, ops.SetLocal, ops.TeeLocal, ops.GetGlobal, ops.SetGlobal: index, err := leb128.ReadVarUint32(reader) if err != nil { return nil, err } instr.Immediates = append(instr.Immediates, index) + + if !instr.Unreachable { + top := stackDepths.Top() + switch op { + case ops.GetLocal, ops.GetGlobal: + top++ + stackDepths.SetTop(top) + disas.checkMaxDepth(int(top)) + case ops.SetLocal, ops.SetGlobal: + top-- + stackDepths.SetTop(top) + case ops.TeeLocal: + // stack remains unchanged for tee_local + } + } case ops.I32Const: i, err := leb128.ReadVarint32(reader) if err != nil { @@ -217,7 +446,18 @@ func Disassemble(fn wasm.Function, module *wasm.Module) (*Disassembly, error) { instr.Immediates = append(instr.Immediates, uint8(res)) } + if op != ops.Return { + lastOpReturn = false + } + disas.Code = append(disas.Code, instr) + curIndex++ + } + + if logging { + for _, instr := range disas.Code { + logger.Printf("%v %v", instr.Op.Name, instr.NewStack) + } } return disas, nil diff --git a/vendor/github.com/go-interpreter/wagon/internal/stack/stack.go b/vendor/github.com/go-interpreter/wagon/internal/stack/stack.go new file mode 100644 index 0000000..4481da0 --- /dev/null +++ b/vendor/github.com/go-interpreter/wagon/internal/stack/stack.go @@ -0,0 +1,40 @@ +// Copyright 2017 The go-interpreter 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 stack implements a growable uint64 stack +package stack + +type Stack struct { + slice []uint64 +} + +func (s *Stack) Push(b uint64) { + s.slice = append(s.slice, b) +} + +func (s *Stack) Pop() uint64 { + v := s.Top() + s.slice = s.slice[:len(s.slice)-1] + return v +} + +func (s *Stack) SetTop(v uint64) { + s.slice[len(s.slice)-1] = v +} + +func (s *Stack) Top() uint64 { + return s.slice[len(s.slice)-1] +} + +func (s *Stack) Get(i int) uint64 { + return s.slice[i] +} + +func (s *Stack) Set(i int, v uint64) { + s.slice[i] = v +} + +func (s *Stack) Len() int { + return len(s.slice) +} diff --git a/vendor/github.com/go-interpreter/wagon/wasm/encode.go b/vendor/github.com/go-interpreter/wagon/wasm/encode.go index be54869..ef90a28 100644 --- a/vendor/github.com/go-interpreter/wagon/wasm/encode.go +++ b/vendor/github.com/go-interpreter/wagon/wasm/encode.go @@ -22,7 +22,43 @@ func EncodeModule(w io.Writer, m *Module) error { if err := writeU32(w, currentVersion); err != nil { return err } - sections := m.Sections + var sections []Section + if m.Types != nil { + sections = append(sections, m.Types) + } + if m.Import != nil { + sections = append(sections, m.Import) + } + if m.Function != nil { + sections = append(sections, m.Function) + } + if m.Table != nil { + sections = append(sections, m.Table) + } + if m.Memory != nil { + sections = append(sections, m.Memory) + } + if m.Global != nil { + sections = append(sections, m.Global) + } + if m.Export != nil { + sections = append(sections, m.Export) + } + if m.Start != nil { + sections = append(sections, m.Start) + } + if m.Elements != nil { + sections = append(sections, m.Elements) + } + if m.Code != nil { + sections = append(sections, m.Code) + } + if m.Data != nil { + sections = append(sections, m.Data) + } + for i := range m.Other { + sections = append(sections, &m.Other[i]) + } buf := new(bytes.Buffer) for _, s := range sections { if _, err := leb128.WriteVarUint32(w, uint32(s.SectionID())); err != nil { diff --git a/vendor/github.com/go-interpreter/wagon/wasm/index.go b/vendor/github.com/go-interpreter/wagon/wasm/index.go index 946b75f..70719d5 100644 --- a/vendor/github.com/go-interpreter/wagon/wasm/index.go +++ b/vendor/github.com/go-interpreter/wagon/wasm/index.go @@ -92,7 +92,7 @@ func (m *Module) populateTables() error { if m.Table == nil || len(m.Table.Entries) == 0 || m.Elements == nil || len(m.Elements.Entries) == 0 { return nil } -/* + for _, elem := range m.Elements.Entries { // the MVP dictates that index should always be zero, we shuold // probably check this @@ -106,7 +106,7 @@ func (m *Module) populateTables() error { } offset, ok := val.(int32) if !ok { - return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(val).Kind()} + return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(offset).Kind()} } table := m.TableIndexSpace[int(elem.Index)] @@ -119,7 +119,7 @@ func (m *Module) populateTables() error { copy(table[int(offset):], elem.Elems) m.TableIndexSpace[int(elem.Index)] = table } - }*/ + } logger.Printf("There are %d entries in the table index space.", len(m.TableIndexSpace)) return nil @@ -140,7 +140,7 @@ func (m *Module) populateLinearMemory() error { return nil } // each module can only have a single linear memory in the MVP -/* + for _, entry := range m.Data.Entries { if entry.Index != 0 { return InvalidLinearMemoryIndexError(entry.Index) @@ -152,7 +152,7 @@ func (m *Module) populateLinearMemory() error { } offset, ok := val.(int32) if !ok { - return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(val).Kind()} + return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(offset).Kind()} } memory := m.LinearMemoryIndexSpace[int(entry.Index)] @@ -165,7 +165,7 @@ func (m *Module) populateLinearMemory() error { copy(memory[int(offset):], entry.Data) m.LinearMemoryIndexSpace[int(entry.Index)] = memory } - }*/ + } return nil } diff --git a/vendor/github.com/go-interpreter/wagon/wasm/module.go b/vendor/github.com/go-interpreter/wagon/wasm/module.go index 6a510b0..00f69d9 100644 --- a/vendor/github.com/go-interpreter/wagon/wasm/module.go +++ b/vendor/github.com/go-interpreter/wagon/wasm/module.go @@ -35,8 +35,7 @@ func (fct *Function) IsHost() bool { // Module represents a parsed WebAssembly module: // http://webassembly.org/docs/modules/ type Module struct { - Version uint32 - Sections []Section + Version uint32 Types *SectionTypes Import *SectionImports @@ -49,7 +48,6 @@ type Module struct { Elements *SectionElements Code *SectionCode Data *SectionData - Customs []*SectionCustom // The function index space of the module FunctionIndexSpace []Function @@ -60,6 +58,8 @@ type Module struct { TableIndexSpace [][]uint32 LinearMemoryIndexSpace [][]byte + Other []RawSection // Other holds the custom sections if any + imports struct { Funcs []uint32 Globals int @@ -68,16 +68,6 @@ type Module struct { } } -// Custom returns a custom section with a specific name, if it exists. -func (m *Module) Custom(name string) *SectionCustom { - for _, s := range m.Customs { - if s.Name == name { - return s - } - } - return nil -} - // NewModule creates a new empty module func NewModule() *Module { return &Module{ diff --git a/vendor/github.com/go-interpreter/wagon/wasm/read.go b/vendor/github.com/go-interpreter/wagon/wasm/read.go index 4625b05..7aae83b 100644 --- a/vendor/github.com/go-interpreter/wagon/wasm/read.go +++ b/vendor/github.com/go-interpreter/wagon/wasm/read.go @@ -7,8 +7,6 @@ package wasm import ( "encoding/binary" "io" - - "github.com/go-interpreter/wagon/wasm/leb128" ) func readBytes(r io.Reader, n int) ([]byte, error) { @@ -21,14 +19,6 @@ func readBytes(r io.Reader, n int) ([]byte, error) { return bytes, nil } -func readBytesUint(r io.Reader) ([]byte, error) { - n, err := leb128.ReadVarUint32(r) - if err != nil { - return nil, err - } - return readBytes(r, int(n)) -} - func readString(r io.Reader, n int) (string, error) { bytes, err := readBytes(r, n) if err != nil { @@ -37,14 +27,6 @@ func readString(r io.Reader, n int) (string, error) { return string(bytes), nil } -func readStringUint(r io.Reader) (string, error) { - n, err := leb128.ReadVarUint32(r) - if err != nil { - return "", err - } - return readString(r, int(n)) -} - func readU32(r io.Reader) (uint32, error) { var buf [4]byte _, err := io.ReadFull(r, buf[:]) diff --git a/vendor/github.com/go-interpreter/wagon/wasm/section.go b/vendor/github.com/go-interpreter/wagon/wasm/section.go index 026c539..8b59e66 100644 --- a/vendor/github.com/go-interpreter/wagon/wasm/section.go +++ b/vendor/github.com/go-interpreter/wagon/wasm/section.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "sort" "github.com/go-interpreter/wagon/wasm/internal/readpos" @@ -73,7 +72,11 @@ type RawSection struct { Start int64 End int64 - ID SectionID + ID SectionID + // Size of this section in bytes + PayloadLen uint32 + // Section name, empty if id != 0 + Name string Bytes []byte } @@ -81,6 +84,17 @@ func (s *RawSection) SectionID() SectionID { return s.ID } +func (s *RawSection) ReadPayload(r io.Reader) error { + s.Bytes = make([]byte, s.PayloadLen) + _, err := io.ReadFull(r, s.Bytes) + return err +} + +func (s *RawSection) WritePayload(w io.Writer) error { + _, err := w.Write(s.Bytes) + return err +} + func (s *RawSection) GetRawSection() *RawSection { return s } @@ -112,19 +126,32 @@ func (m *Module) readSection(r *readpos.ReadPos) (bool, error) { var id uint32 logger.Println("Reading section ID") - id, err = leb128.ReadVarUint32(r) - if err == io.EOF { - return true, nil - } else if err != nil { + if id, err = leb128.ReadVarUint32(r); err != nil { + if err == io.EOF { // no bytes were read, the reader is empty + return true, nil + } return false, err } s := RawSection{ID: SectionID(id)} logger.Println("Reading payload length") + if s.PayloadLen, err = leb128.ReadVarUint32(r); err != nil { + return false, nil + } - payloadDataLen, err := leb128.ReadVarUint32(r) - if err != nil { - return false, err + payloadDataLen := s.PayloadLen + + if s.ID == SectionIDCustom { + nameLen, nameLenSize, err := leb128.ReadVarUint32Size(r) + if err != nil { + return false, err + } + payloadDataLen -= uint32(nameLenSize) + if s.Name, err = readString(r, int(nameLen)); err != nil { + return false, err + } + + payloadDataLen -= uint32(len(s.Name)) } logger.Printf("Section payload length: %d", payloadDataLen) @@ -139,9 +166,9 @@ func (m *Module) readSection(r *readpos.ReadPos) (bool, error) { switch s.ID { case SectionIDCustom: logger.Println("section custom") - cs := &SectionCustom{} - m.Customs = append(m.Customs, cs) - sec = cs + i := len(m.Other) + m.Other = append(m.Other, s) + sec = &m.Other[i] case SectionIDType: logger.Println("section type") m.Types = &SectionTypes{} @@ -213,44 +240,9 @@ func (m *Module) readSection(r *readpos.ReadPos) (bool, error) { s.Bodies[i].Module = m } } - m.Sections = append(m.Sections, sec) return false, nil } -var _ Section = (*SectionCustom)(nil) - -type SectionCustom struct { - RawSection - Name string - Data []byte -} - -func (s *SectionCustom) SectionID() SectionID { - return SectionIDCustom -} - -func (s *SectionCustom) ReadPayload(r io.Reader) error { - var err error - s.Name, err = readStringUint(r) - if err != nil { - return err - } - data, err := ioutil.ReadAll(r) - if err != nil { - return err - } - s.Data = data - return nil -} - -func (s *SectionCustom) WritePayload(w io.Writer) error { - if err := writeStringUint(w, s.Name); err != nil { - return err - } - _, err := w.Write(s.Data) - return err -} - var _ Section = (*SectionTypes)(nil) // SectionTypes declares all function signatures that will be used in a module. @@ -332,15 +324,23 @@ func (s *SectionImports) WritePayload(w io.Writer) error { } func (i *ImportEntry) UnmarshalWASM(r io.Reader) error { - var err error - i.ModuleName, err = readStringUint(r) + modLen, err := leb128.ReadVarUint32(r) if err != nil { return err } - i.FieldName, err = readStringUint(r) + + if i.ModuleName, err = readString(r, int(modLen)); err != nil { + return err + } + + fieldLen, err := leb128.ReadVarUint32(r) if err != nil { return err } + + if i.FieldName, err = readString(r, int(fieldLen)); err != nil { + return err + } var kind External err = kind.UnmarshalWASM(r) if err != nil { @@ -637,12 +637,15 @@ type ExportEntry struct { } func (e *ExportEntry) UnmarshalWASM(r io.Reader) error { - var err error - e.FieldStr, err = readStringUint(r) + fieldLen, err := leb128.ReadVarUint32(r) if err != nil { return err } + if e.FieldStr, err = readString(r, int(fieldLen)); err != nil { + return err + } + if err := e.Kind.UnmarshalWASM(r); err != nil { return err } @@ -964,240 +967,22 @@ func (s *DataSegment) UnmarshalWASM(r io.Reader) error { if s.Offset, err = readInitExpr(r); err != nil { return err } - s.Data, err = readBytesUint(r) - return err -} - -func (s *DataSegment) MarshalWASM(w io.Writer) error { - if _, err := leb128.WriteVarUint32(w, s.Index); err != nil { - return err - } - if _, err := w.Write(s.Offset); err != nil { - return err - } - return writeBytesUint(w, s.Data) -} - -// A list of well-known custom sections -const ( - CustomSectionName = "name" -) - -var ( - _ Marshaler = (*NameSection)(nil) - _ Unmarshaler = (*NameSection)(nil) -) - -// NameType is the type of name subsection. -type NameType byte - -const ( - NameModule = NameType(0) - NameFunction = NameType(1) - NameLocal = NameType(2) -) - -// NameSection is a custom section that stores names of modules, functions and locals for debugging purposes. -// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#name-section for more details. -type NameSection struct { - Types map[NameType][]byte -} - -func (s *NameSection) UnmarshalWASM(r io.Reader) error { - s.Types = make(map[NameType][]byte) - for { - typ, err := leb128.ReadVarUint32(r) - if err == io.EOF { - return nil - } else if err != nil { - return err - } - data, err := readBytesUint(r) - if err != nil { - return err - } - s.Types[NameType(typ)] = data - } -} - -func (s *NameSection) MarshalWASM(w io.Writer) error { - keys := make([]NameType, 0, len(s.Types)) - for k := range s.Types { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { - return keys[i] < keys[j] - }) - for _, k := range keys { - data := s.Types[k] - if _, err := leb128.WriteVarUint32(w, uint32(k)); err != nil { - return err - } - if err := writeBytesUint(w, data); err != nil { - return err - } - } - return nil -} - -// Decode finds a specific subsection type and decodes it. -func (s *NameSection) Decode(typ NameType) (NameSubsection, error) { - var sub NameSubsection - switch typ { - case NameModule: - sub = &ModuleName{} - case NameFunction: - sub = &FunctionNames{} - case NameLocal: - sub = &LocalNames{} - default: - return nil, fmt.Errorf("unsupported name subsection: %x", typ) - } - data, ok := s.Types[typ] - if !ok { - return nil, nil - } - if err := sub.UnmarshalWASM(bytes.NewReader(data)); err != nil { - return nil, err - } - return sub, nil -} - -// NameSubsection is an interface for subsections of NameSection. -// -// Valid types: -// * ModuleName -// * FunctionNames -// * LocalNames -type NameSubsection interface { - Marshaler - Unmarshaler - isNameSubsection() -} - -// ModuleName is the name of a module. -type ModuleName struct { - Name string -} -func (*ModuleName) isNameSubsection() {} - -func (s *ModuleName) UnmarshalWASM(r io.Reader) error { - var err error - s.Name, err = readStringUint(r) - return err -} - -func (s *ModuleName) MarshalWASM(w io.Writer) error { - return writeStringUint(w, s.Name) -} - -// FunctionNames is a set of names for functions. -type FunctionNames struct { - Names NameMap -} - -func (*FunctionNames) isNameSubsection() {} - -func (s *FunctionNames) UnmarshalWASM(r io.Reader) error { - s.Names = make(NameMap) - return s.Names.UnmarshalWASM(r) -} - -func (s *FunctionNames) MarshalWASM(w io.Writer) error { - return s.Names.MarshalWASM(w) -} - -// LocalNames is a set of local variable names for functions. -type LocalNames struct { - // Funcs maps a function index to a set of variable names. - Funcs map[uint32]NameMap -} - -func (*LocalNames) isNameSubsection() {} - -func (s *LocalNames) UnmarshalWASM(r io.Reader) error { - s.Funcs = make(map[uint32]NameMap) size, err := leb128.ReadVarUint32(r) if err != nil { return err } - for i := 0; i < int(size); i++ { - ind, err := leb128.ReadVarUint32(r) - if err != nil { - return err - } - m := make(NameMap) - if err := m.UnmarshalWASM(r); err != nil { - return err - } - s.Funcs[ind] = m - } - return nil -} + s.Data, err = readBytes(r, int(size)) -func (s *LocalNames) MarshalWASM(w io.Writer) error { - keys := make([]uint32, 0, len(s.Funcs)) - for k := range s.Funcs { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { - return keys[i] < keys[j] - }) - for _, k := range keys { - m := s.Funcs[k] - if _, err := leb128.WriteVarUint32(w, k); err != nil { - return err - } - if err := m.MarshalWASM(w); err != nil { - return err - } - } - return nil + return err } -var ( - _ Marshaler = (NameMap)(nil) - _ Unmarshaler = (NameMap)(nil) -) - -// NameMap maps an index of the entry to a name. -type NameMap map[uint32]string - -func (m NameMap) UnmarshalWASM(r io.Reader) error { - size, err := leb128.ReadVarUint32(r) - if err != nil { +func (s *DataSegment) MarshalWASM(w io.Writer) error { + if _, err := leb128.WriteVarUint32(w, s.Index); err != nil { return err } - for i := 0; i < int(size); i++ { - ind, err := leb128.ReadVarUint32(r) - if err != nil { - return err - } - name, err := readStringUint(r) - if err != nil { - return err - } - m[ind] = name - } - return nil -} -func (m NameMap) MarshalWASM(w io.Writer) error { - keys := make([]uint32, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Slice(keys, func(i, j int) bool { - return keys[i] < keys[j] - }) - for _, k := range keys { - name := m[k] - if _, err := leb128.WriteVarUint32(w, k); err != nil { - return err - } - if err := writeStringUint(w, name); err != nil { - return err - } + if _, err := w.Write(s.Offset); err != nil { + return err } - return nil + return writeBytesUint(w, s.Data) } diff --git a/vendor/github.com/gogo/protobuf/proto/decode.go b/vendor/github.com/gogo/protobuf/proto/decode.go index d9aa3c4..63b0f08 100644 --- a/vendor/github.com/gogo/protobuf/proto/decode.go +++ b/vendor/github.com/gogo/protobuf/proto/decode.go @@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) { if b&0x80 == 0 { goto done } - // x -= 0x80 << 63 // Always zero. return 0, errOverflow diff --git a/vendor/github.com/gogo/protobuf/proto/deprecated.go b/vendor/github.com/gogo/protobuf/proto/deprecated.go new file mode 100644 index 0000000..35b882c --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/deprecated.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import "errors" + +// Deprecated: do not use. +type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } + +// Deprecated: do not use. +func GetStats() Stats { return Stats{} } + +// Deprecated: do not use. +func MarshalMessageSet(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSet([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func MarshalMessageSetJSON(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSetJSON([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions.go b/vendor/github.com/gogo/protobuf/proto/extensions.go index 44ebd45..686bd2a 100644 --- a/vendor/github.com/gogo/protobuf/proto/extensions.go +++ b/vendor/github.com/gogo/protobuf/proto/extensions.go @@ -544,7 +544,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { - return errors.New("proto: bad extension value type") + return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) } // nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go index b2271d0..d17f802 100644 --- a/vendor/github.com/gogo/protobuf/proto/lib.go +++ b/vendor/github.com/gogo/protobuf/proto/lib.go @@ -341,26 +341,6 @@ type Message interface { ProtoMessage() } -// Stats records allocation details about the protocol buffer encoders -// and decoders. Useful for tuning the library itself. -type Stats struct { - Emalloc uint64 // mallocs in encode - Dmalloc uint64 // mallocs in decode - Encode uint64 // number of encodes - Decode uint64 // number of decodes - Chit uint64 // number of cache hits - Cmiss uint64 // number of cache misses - Size uint64 // number of sizes -} - -// Set to true to enable stats collection. -const collectStats = false - -var stats Stats - -// GetStats returns a copy of the global Stats structure. -func GetStats() Stats { return stats } - // A Buffer is a buffer manager for marshaling and unmarshaling // protocol buffers. It may be reused between invocations to // reduce memory usage. It is not necessary to use a Buffer; diff --git a/vendor/github.com/gogo/protobuf/proto/message_set.go b/vendor/github.com/gogo/protobuf/proto/message_set.go index 3b6ca41..f48a756 100644 --- a/vendor/github.com/gogo/protobuf/proto/message_set.go +++ b/vendor/github.com/gogo/protobuf/proto/message_set.go @@ -36,13 +36,7 @@ package proto */ import ( - "bytes" - "encoding/json" "errors" - "fmt" - "reflect" - "sort" - "sync" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. @@ -145,46 +139,9 @@ func skipVarint(buf []byte) []byte { return buf[i+1:] } -// MarshalMessageSet encodes the extension map represented by m in the message set wire format. -// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(exts interface{}) ([]byte, error) { - return marshalMessageSet(exts, false) -} - -// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal. -func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) { - switch exts := exts.(type) { - case *XXX_InternalExtensions: - var u marshalInfo - siz := u.sizeMessageSet(exts) - b := make([]byte, 0, siz) - return u.appendMessageSet(b, exts, deterministic) - - case map[int32]Extension: - // This is an old-style extension map. - // Wrap it in a new-style XXX_InternalExtensions. - ie := XXX_InternalExtensions{ - p: &struct { - mu sync.Mutex - extensionMap map[int32]Extension - }{ - extensionMap: exts, - }, - } - - var u marshalInfo - siz := u.sizeMessageSet(&ie) - b := make([]byte, 0, siz) - return u.appendMessageSet(b, &ie, deterministic) - - default: - return nil, errors.New("proto: not an extension map") - } -} - -// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, exts interface{}) error { +func unmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: @@ -222,93 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error { } return nil } - -// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. -// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - var mu sync.Locker - m, mu = exts.extensionsRead() - if m != nil { - // Keep the extensions map locked until we're done marshaling to prevent - // races between marshaling and unmarshaling the lazily-{en,de}coded - // values. - mu.Lock() - defer mu.Unlock() - } - case map[int32]Extension: - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - var b bytes.Buffer - b.WriteByte('{') - - // Process the map in key order for deterministic output. - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) // int32Slice defined in text.go - - for i, id := range ids { - ext := m[id] - msd, ok := messageSetMap[id] - if !ok { - // Unknown type; we can't render it, so skip it. - continue - } - - if i > 0 && b.Len() > 1 { - b.WriteByte(',') - } - - fmt.Fprintf(&b, `"[%s]":`, msd.name) - - x := ext.value - if x == nil { - x = reflect.New(msd.t.Elem()).Interface() - if err := Unmarshal(ext.enc, x.(Message)); err != nil { - return nil, err - } - } - d, err := json.Marshal(x) - if err != nil { - return nil, err - } - b.Write(d) - } - b.WriteByte('}') - return b.Bytes(), nil -} - -// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. -// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { - // Common-case fast path. - if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { - return nil - } - - // This is fairly tricky, and it's not clear that it is needed. - return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") -} - -// A global registry of types that can be used in a MessageSet. - -var messageSetMap = make(map[int32]messageSetDesc) - -type messageSetDesc struct { - t reflect.Type // pointer to struct - name string -} - -// RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(m Message, fieldNum int32, name string) { - messageSetMap[fieldNum] = messageSetDesc{ - t: reflect.TypeOf(m), - name: name, - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/properties.go b/vendor/github.com/gogo/protobuf/proto/properties.go index 04dcb8d..c9e5fa0 100644 --- a/vendor/github.com/gogo/protobuf/proto/properties.go +++ b/vendor/github.com/gogo/protobuf/proto/properties.go @@ -391,9 +391,6 @@ func GetProperties(t reflect.Type) *StructProperties { sprop, ok := propertiesMap[t] propertiesMu.RUnlock() if ok { - if collectStats { - stats.Chit++ - } return sprop } @@ -406,14 +403,8 @@ func GetProperties(t reflect.Type) *StructProperties { // getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { - if collectStats { - stats.Chit++ - } return prop } - if collectStats { - stats.Cmiss++ - } prop := new(StructProperties) // in case of recursive protos, fill this in now. diff --git a/vendor/github.com/gogo/protobuf/proto/table_marshal.go b/vendor/github.com/gogo/protobuf/proto/table_marshal.go index ba58c49..9b1538d 100644 --- a/vendor/github.com/gogo/protobuf/proto/table_marshal.go +++ b/vendor/github.com/gogo/protobuf/proto/table_marshal.go @@ -491,7 +491,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { fi.field = toField(f) - fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. fi.isPointer = true fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go index e6b15c7..bb2622f 100644 --- a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go +++ b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go @@ -138,7 +138,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error { u.computeUnmarshalInfo() } if u.isMessageSet { - return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) + return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) } var reqMask uint64 // bitmask of required fields we've seen. var errLater error @@ -2142,7 +2142,7 @@ func encodeVarint(b []byte, x uint64) []byte { // If there is an error, it returns 0,0. func decodeVarint(b []byte) (uint64, int) { var x, y uint64 - if len(b) <= 0 { + if len(b) == 0 { goto bad } x = uint64(b[0]) diff --git a/vendor/github.com/golang/snappy/go.mod b/vendor/github.com/golang/snappy/go.mod new file mode 100644 index 0000000..f6406bb --- /dev/null +++ b/vendor/github.com/golang/snappy/go.mod @@ -0,0 +1 @@ +module github.com/golang/snappy diff --git a/vendor/github.com/spaolacci/murmur3/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore similarity index 94% rename from vendor/github.com/spaolacci/murmur3/.gitignore rename to vendor/github.com/gorilla/websocket/.gitignore index 0026861..cd3fcd1 100644 --- a/vendor/github.com/spaolacci/murmur3/.gitignore +++ b/vendor/github.com/gorilla/websocket/.gitignore @@ -20,3 +20,6 @@ _cgo_export.* _testmain.go *.exe + +.idea/ +*.iml diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml new file mode 100644 index 0000000..a49db51 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/.travis.yml @@ -0,0 +1,19 @@ +language: go +sudo: false + +matrix: + include: + - go: 1.7.x + - go: 1.8.x + - go: 1.9.x + - go: 1.10.x + - go: 1.11.x + - go: tip + allow_failures: + - go: tip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go vet $(go list ./... | grep -v /vendor/) + - go test -v -race ./... diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS new file mode 100644 index 0000000..1931f40 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/AUTHORS @@ -0,0 +1,9 @@ +# This is the official list of Gorilla WebSocket authors for copyright +# purposes. +# +# Please keep the list sorted. + +Gary Burd +Google LLC (https://opensource.google.com/) +Joachim Bauch + diff --git a/vendor/github.com/gorilla/websocket/LICENSE b/vendor/github.com/gorilla/websocket/LICENSE new file mode 100644 index 0000000..9171c97 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md new file mode 100644 index 0000000..20e391f --- /dev/null +++ b/vendor/github.com/gorilla/websocket/README.md @@ -0,0 +1,64 @@ +# Gorilla WebSocket + +Gorilla WebSocket is a [Go](http://golang.org/) implementation of the +[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. + +[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket) +[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) + +### Documentation + +* [API Reference](http://godoc.org/github.com/gorilla/websocket) +* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) +* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) +* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) +* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) + +### Status + +The Gorilla WebSocket package provides a complete and tested implementation of +the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The +package API is stable. + +### Installation + + go get github.com/gorilla/websocket + +### Protocol Compliance + +The Gorilla WebSocket package passes the server tests in the [Autobahn Test +Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn +subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). + +### Gorilla WebSocket compared with other packages + + + + + + + + + + + + + + + + + + +
github.com/gorillagolang.org/x/net
RFC 6455 Features
Passes Autobahn Test SuiteYesNo
Receive fragmented messageYesNo, see note 1
Send close messageYesNo
Send pings and receive pongsYesNo
Get the type of a received data messageYesYes, see note 2
Other Features
Compression ExtensionsExperimentalNo
Read message using io.ReaderYesNo, see note 3
Write message using io.WriteCloserYesNo, see note 3
+ +Notes: + +1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). +2. The application can get the type of a received data message by implementing + a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) + function. +3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. + Read returns when the input buffer is full or a frame boundary is + encountered. Each call to Write sends a single frame message. The Gorilla + io.Reader and io.WriteCloser operate on a single WebSocket message. + diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go new file mode 100644 index 0000000..2e32fd5 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client.go @@ -0,0 +1,395 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "io" + "io/ioutil" + "net" + "net/http" + "net/http/httptrace" + "net/url" + "strings" + "time" +) + +// ErrBadHandshake is returned when the server response to opening handshake is +// invalid. +var ErrBadHandshake = errors.New("websocket: bad handshake") + +var errInvalidCompression = errors.New("websocket: invalid compression negotiation") + +// NewClient creates a new client connection using the given net connection. +// The URL u specifies the host and request URI. Use requestHeader to specify +// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies +// (Cookie). Use the response.Header to get the selected subprotocol +// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). +// +// If the WebSocket handshake fails, ErrBadHandshake is returned along with a +// non-nil *http.Response so that callers can handle redirects, authentication, +// etc. +// +// Deprecated: Use Dialer instead. +func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) { + d := Dialer{ + ReadBufferSize: readBufSize, + WriteBufferSize: writeBufSize, + NetDial: func(net, addr string) (net.Conn, error) { + return netConn, nil + }, + } + return d.Dial(u.String(), requestHeader) +} + +// A Dialer contains options for connecting to WebSocket server. +type Dialer struct { + // NetDial specifies the dial function for creating TCP connections. If + // NetDial is nil, net.Dial is used. + NetDial func(network, addr string) (net.Conn, error) + + // NetDialContext specifies the dial function for creating TCP connections. If + // NetDialContext is nil, net.DialContext is used. + NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error) + + // Proxy specifies a function to return a proxy for a given + // Request. If the function returns a non-nil error, the + // request is aborted with the provided error. + // If Proxy is nil or returns a nil *URL, no proxy is used. + Proxy func(*http.Request) (*url.URL, error) + + // TLSClientConfig specifies the TLS configuration to use with tls.Client. + // If nil, the default configuration is used. + TLSClientConfig *tls.Config + + // HandshakeTimeout specifies the duration for the handshake to complete. + HandshakeTimeout time.Duration + + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then a useful default size is used. The I/O buffer sizes + // do not limit the size of the messages that can be sent or received. + ReadBufferSize, WriteBufferSize int + + // WriteBufferPool is a pool of buffers for write operations. If the value + // is not set, then write buffers are allocated to the connection for the + // lifetime of the connection. + // + // A pool is most useful when the application has a modest volume of writes + // across a large number of connections. + // + // Applications should use a single pool for each unique value of + // WriteBufferSize. + WriteBufferPool BufferPool + + // Subprotocols specifies the client's requested subprotocols. + Subprotocols []string + + // EnableCompression specifies if the client should attempt to negotiate + // per message compression (RFC 7692). Setting this value to true does not + // guarantee that compression will be supported. Currently only "no context + // takeover" modes are supported. + EnableCompression bool + + // Jar specifies the cookie jar. + // If Jar is nil, cookies are not sent in requests and ignored + // in responses. + Jar http.CookieJar +} + +// Dial creates a new client connection by calling DialContext with a background context. +func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { + return d.DialContext(context.Background(), urlStr, requestHeader) +} + +var errMalformedURL = errors.New("malformed ws or wss URL") + +func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { + hostPort = u.Host + hostNoPort = u.Host + if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { + hostNoPort = hostNoPort[:i] + } else { + switch u.Scheme { + case "wss": + hostPort += ":443" + case "https": + hostPort += ":443" + default: + hostPort += ":80" + } + } + return hostPort, hostNoPort +} + +// DefaultDialer is a dialer with all fields set to the default values. +var DefaultDialer = &Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 45 * time.Second, +} + +// nilDialer is dialer to use when receiver is nil. +var nilDialer = *DefaultDialer + +// DialContext creates a new client connection. Use requestHeader to specify the +// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie). +// Use the response.Header to get the selected subprotocol +// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). +// +// The context will be used in the request and in the Dialer +// +// If the WebSocket handshake fails, ErrBadHandshake is returned along with a +// non-nil *http.Response so that callers can handle redirects, authentication, +// etcetera. The response body may not contain the entire response and does not +// need to be closed by the application. +func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { + if d == nil { + d = &nilDialer + } + + challengeKey, err := generateChallengeKey() + if err != nil { + return nil, nil, err + } + + u, err := url.Parse(urlStr) + if err != nil { + return nil, nil, err + } + + switch u.Scheme { + case "ws": + u.Scheme = "http" + case "wss": + u.Scheme = "https" + default: + return nil, nil, errMalformedURL + } + + if u.User != nil { + // User name and password are not allowed in websocket URIs. + return nil, nil, errMalformedURL + } + + req := &http.Request{ + Method: "GET", + URL: u, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + Host: u.Host, + } + req = req.WithContext(ctx) + + // Set the cookies present in the cookie jar of the dialer + if d.Jar != nil { + for _, cookie := range d.Jar.Cookies(u) { + req.AddCookie(cookie) + } + } + + // Set the request headers using the capitalization for names and values in + // RFC examples. Although the capitalization shouldn't matter, there are + // servers that depend on it. The Header.Set method is not used because the + // method canonicalizes the header names. + req.Header["Upgrade"] = []string{"websocket"} + req.Header["Connection"] = []string{"Upgrade"} + req.Header["Sec-WebSocket-Key"] = []string{challengeKey} + req.Header["Sec-WebSocket-Version"] = []string{"13"} + if len(d.Subprotocols) > 0 { + req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")} + } + for k, vs := range requestHeader { + switch { + case k == "Host": + if len(vs) > 0 { + req.Host = vs[0] + } + case k == "Upgrade" || + k == "Connection" || + k == "Sec-Websocket-Key" || + k == "Sec-Websocket-Version" || + k == "Sec-Websocket-Extensions" || + (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): + return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) + case k == "Sec-Websocket-Protocol": + req.Header["Sec-WebSocket-Protocol"] = vs + default: + req.Header[k] = vs + } + } + + if d.EnableCompression { + req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"} + } + + if d.HandshakeTimeout != 0 { + var cancel func() + ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout) + defer cancel() + } + + // Get network dial function. + var netDial func(network, add string) (net.Conn, error) + + if d.NetDialContext != nil { + netDial = func(network, addr string) (net.Conn, error) { + return d.NetDialContext(ctx, network, addr) + } + } else if d.NetDial != nil { + netDial = d.NetDial + } else { + netDialer := &net.Dialer{} + netDial = func(network, addr string) (net.Conn, error) { + return netDialer.DialContext(ctx, network, addr) + } + } + + // If needed, wrap the dial function to set the connection deadline. + if deadline, ok := ctx.Deadline(); ok { + forwardDial := netDial + netDial = func(network, addr string) (net.Conn, error) { + c, err := forwardDial(network, addr) + if err != nil { + return nil, err + } + err = c.SetDeadline(deadline) + if err != nil { + c.Close() + return nil, err + } + return c, nil + } + } + + // If needed, wrap the dial function to connect through a proxy. + if d.Proxy != nil { + proxyURL, err := d.Proxy(req) + if err != nil { + return nil, nil, err + } + if proxyURL != nil { + dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) + if err != nil { + return nil, nil, err + } + netDial = dialer.Dial + } + } + + hostPort, hostNoPort := hostPortNoPort(u) + trace := httptrace.ContextClientTrace(ctx) + if trace != nil && trace.GetConn != nil { + trace.GetConn(hostPort) + } + + netConn, err := netDial("tcp", hostPort) + if trace != nil && trace.GotConn != nil { + trace.GotConn(httptrace.GotConnInfo{ + Conn: netConn, + }) + } + if err != nil { + return nil, nil, err + } + + defer func() { + if netConn != nil { + netConn.Close() + } + }() + + if u.Scheme == "https" { + cfg := cloneTLSConfig(d.TLSClientConfig) + if cfg.ServerName == "" { + cfg.ServerName = hostNoPort + } + tlsConn := tls.Client(netConn, cfg) + netConn = tlsConn + + var err error + if trace != nil { + err = doHandshakeWithTrace(trace, tlsConn, cfg) + } else { + err = doHandshake(tlsConn, cfg) + } + + if err != nil { + return nil, nil, err + } + } + + conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil) + + if err := req.Write(netConn); err != nil { + return nil, nil, err + } + + if trace != nil && trace.GotFirstResponseByte != nil { + if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 { + trace.GotFirstResponseByte() + } + } + + resp, err := http.ReadResponse(conn.br, req) + if err != nil { + return nil, nil, err + } + + if d.Jar != nil { + if rc := resp.Cookies(); len(rc) > 0 { + d.Jar.SetCookies(u, rc) + } + } + + if resp.StatusCode != 101 || + !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || + !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || + resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) { + // Before closing the network connection on return from this + // function, slurp up some of the response to aid application + // debugging. + buf := make([]byte, 1024) + n, _ := io.ReadFull(resp.Body, buf) + resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) + return nil, resp, ErrBadHandshake + } + + for _, ext := range parseExtensions(resp.Header) { + if ext[""] != "permessage-deflate" { + continue + } + _, snct := ext["server_no_context_takeover"] + _, cnct := ext["client_no_context_takeover"] + if !snct || !cnct { + return nil, resp, errInvalidCompression + } + conn.newCompressionWriter = compressNoContextTakeover + conn.newDecompressionReader = decompressNoContextTakeover + break + } + + resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") + + netConn.SetDeadline(time.Time{}) + netConn = nil // to avoid close in defer. + return conn, resp, nil +} + +func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error { + if err := tlsConn.Handshake(); err != nil { + return err + } + if !cfg.InsecureSkipVerify { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go new file mode 100644 index 0000000..4f0d943 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone.go @@ -0,0 +1,16 @@ +// Copyright 2013 The Gorilla WebSocket 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.8 + +package websocket + +import "crypto/tls" + +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return cfg.Clone() +} diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go new file mode 100644 index 0000000..babb007 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone_legacy.go @@ -0,0 +1,38 @@ +// Copyright 2013 The Gorilla WebSocket 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.8 + +package websocket + +import "crypto/tls" + +// cloneTLSConfig clones all public fields except the fields +// SessionTicketsDisabled and SessionTicketKey. This avoids copying the +// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a +// config in active use. +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return &tls.Config{ + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + } +} diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go new file mode 100644 index 0000000..813ffb1 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/compression.go @@ -0,0 +1,148 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "compress/flate" + "errors" + "io" + "strings" + "sync" +) + +const ( + minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6 + maxCompressionLevel = flate.BestCompression + defaultCompressionLevel = 1 +) + +var ( + flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool + flateReaderPool = sync.Pool{New: func() interface{} { + return flate.NewReader(nil) + }} +) + +func decompressNoContextTakeover(r io.Reader) io.ReadCloser { + const tail = + // Add four bytes as specified in RFC + "\x00\x00\xff\xff" + + // Add final block to squelch unexpected EOF error from flate reader. + "\x01\x00\x00\xff\xff" + + fr, _ := flateReaderPool.Get().(io.ReadCloser) + fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) + return &flateReadWrapper{fr} +} + +func isValidCompressionLevel(level int) bool { + return minCompressionLevel <= level && level <= maxCompressionLevel +} + +func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { + p := &flateWriterPools[level-minCompressionLevel] + tw := &truncWriter{w: w} + fw, _ := p.Get().(*flate.Writer) + if fw == nil { + fw, _ = flate.NewWriter(tw, level) + } else { + fw.Reset(tw) + } + return &flateWriteWrapper{fw: fw, tw: tw, p: p} +} + +// truncWriter is an io.Writer that writes all but the last four bytes of the +// stream to another io.Writer. +type truncWriter struct { + w io.WriteCloser + n int + p [4]byte +} + +func (w *truncWriter) Write(p []byte) (int, error) { + n := 0 + + // fill buffer first for simplicity. + if w.n < len(w.p) { + n = copy(w.p[w.n:], p) + p = p[n:] + w.n += n + if len(p) == 0 { + return n, nil + } + } + + m := len(p) + if m > len(w.p) { + m = len(w.p) + } + + if nn, err := w.w.Write(w.p[:m]); err != nil { + return n + nn, err + } + + copy(w.p[:], w.p[m:]) + copy(w.p[len(w.p)-m:], p[len(p)-m:]) + nn, err := w.w.Write(p[:len(p)-m]) + return n + nn, err +} + +type flateWriteWrapper struct { + fw *flate.Writer + tw *truncWriter + p *sync.Pool +} + +func (w *flateWriteWrapper) Write(p []byte) (int, error) { + if w.fw == nil { + return 0, errWriteClosed + } + return w.fw.Write(p) +} + +func (w *flateWriteWrapper) Close() error { + if w.fw == nil { + return errWriteClosed + } + err1 := w.fw.Flush() + w.p.Put(w.fw) + w.fw = nil + if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { + return errors.New("websocket: internal error, unexpected bytes at end of flate stream") + } + err2 := w.tw.w.Close() + if err1 != nil { + return err1 + } + return err2 +} + +type flateReadWrapper struct { + fr io.ReadCloser +} + +func (r *flateReadWrapper) Read(p []byte) (int, error) { + if r.fr == nil { + return 0, io.ErrClosedPipe + } + n, err := r.fr.Read(p) + if err == io.EOF { + // Preemptively place the reader back in the pool. This helps with + // scenarios where the application does not call NextReader() soon after + // this final read. + r.Close() + } + return n, err +} + +func (r *flateReadWrapper) Close() error { + if r.fr == nil { + return io.ErrClosedPipe + } + err := r.fr.Close() + flateReaderPool.Put(r.fr) + r.fr = nil + return err +} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go new file mode 100644 index 0000000..d2a21c1 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -0,0 +1,1165 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket + +import ( + "bufio" + "encoding/binary" + "errors" + "io" + "io/ioutil" + "math/rand" + "net" + "strconv" + "sync" + "time" + "unicode/utf8" +) + +const ( + // Frame header byte 0 bits from Section 5.2 of RFC 6455 + finalBit = 1 << 7 + rsv1Bit = 1 << 6 + rsv2Bit = 1 << 5 + rsv3Bit = 1 << 4 + + // Frame header byte 1 bits from Section 5.2 of RFC 6455 + maskBit = 1 << 7 + + maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask + maxControlFramePayloadSize = 125 + + writeWait = time.Second + + defaultReadBufferSize = 4096 + defaultWriteBufferSize = 4096 + + continuationFrame = 0 + noFrame = -1 +) + +// Close codes defined in RFC 6455, section 11.7. +const ( + CloseNormalClosure = 1000 + CloseGoingAway = 1001 + CloseProtocolError = 1002 + CloseUnsupportedData = 1003 + CloseNoStatusReceived = 1005 + CloseAbnormalClosure = 1006 + CloseInvalidFramePayloadData = 1007 + ClosePolicyViolation = 1008 + CloseMessageTooBig = 1009 + CloseMandatoryExtension = 1010 + CloseInternalServerErr = 1011 + CloseServiceRestart = 1012 + CloseTryAgainLater = 1013 + CloseTLSHandshake = 1015 +) + +// The message types are defined in RFC 6455, section 11.8. +const ( + // TextMessage denotes a text data message. The text message payload is + // interpreted as UTF-8 encoded text data. + TextMessage = 1 + + // BinaryMessage denotes a binary data message. + BinaryMessage = 2 + + // CloseMessage denotes a close control message. The optional message + // payload contains a numeric code and text. Use the FormatCloseMessage + // function to format a close message payload. + CloseMessage = 8 + + // PingMessage denotes a ping control message. The optional message payload + // is UTF-8 encoded text. + PingMessage = 9 + + // PongMessage denotes a pong control message. The optional message payload + // is UTF-8 encoded text. + PongMessage = 10 +) + +// ErrCloseSent is returned when the application writes a message to the +// connection after sending a close message. +var ErrCloseSent = errors.New("websocket: close sent") + +// ErrReadLimit is returned when reading a message that is larger than the +// read limit set for the connection. +var ErrReadLimit = errors.New("websocket: read limit exceeded") + +// netError satisfies the net Error interface. +type netError struct { + msg string + temporary bool + timeout bool +} + +func (e *netError) Error() string { return e.msg } +func (e *netError) Temporary() bool { return e.temporary } +func (e *netError) Timeout() bool { return e.timeout } + +// CloseError represents a close message. +type CloseError struct { + // Code is defined in RFC 6455, section 11.7. + Code int + + // Text is the optional text payload. + Text string +} + +func (e *CloseError) Error() string { + s := []byte("websocket: close ") + s = strconv.AppendInt(s, int64(e.Code), 10) + switch e.Code { + case CloseNormalClosure: + s = append(s, " (normal)"...) + case CloseGoingAway: + s = append(s, " (going away)"...) + case CloseProtocolError: + s = append(s, " (protocol error)"...) + case CloseUnsupportedData: + s = append(s, " (unsupported data)"...) + case CloseNoStatusReceived: + s = append(s, " (no status)"...) + case CloseAbnormalClosure: + s = append(s, " (abnormal closure)"...) + case CloseInvalidFramePayloadData: + s = append(s, " (invalid payload data)"...) + case ClosePolicyViolation: + s = append(s, " (policy violation)"...) + case CloseMessageTooBig: + s = append(s, " (message too big)"...) + case CloseMandatoryExtension: + s = append(s, " (mandatory extension missing)"...) + case CloseInternalServerErr: + s = append(s, " (internal server error)"...) + case CloseTLSHandshake: + s = append(s, " (TLS handshake error)"...) + } + if e.Text != "" { + s = append(s, ": "...) + s = append(s, e.Text...) + } + return string(s) +} + +// IsCloseError returns boolean indicating whether the error is a *CloseError +// with one of the specified codes. +func IsCloseError(err error, codes ...int) bool { + if e, ok := err.(*CloseError); ok { + for _, code := range codes { + if e.Code == code { + return true + } + } + } + return false +} + +// IsUnexpectedCloseError returns boolean indicating whether the error is a +// *CloseError with a code not in the list of expected codes. +func IsUnexpectedCloseError(err error, expectedCodes ...int) bool { + if e, ok := err.(*CloseError); ok { + for _, code := range expectedCodes { + if e.Code == code { + return false + } + } + return true + } + return false +} + +var ( + errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true} + errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()} + errBadWriteOpCode = errors.New("websocket: bad write message type") + errWriteClosed = errors.New("websocket: write closed") + errInvalidControlFrame = errors.New("websocket: invalid control frame") +) + +func newMaskKey() [4]byte { + n := rand.Uint32() + return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} +} + +func hideTempErr(err error) error { + if e, ok := err.(net.Error); ok && e.Temporary() { + err = &netError{msg: e.Error(), timeout: e.Timeout()} + } + return err +} + +func isControl(frameType int) bool { + return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage +} + +func isData(frameType int) bool { + return frameType == TextMessage || frameType == BinaryMessage +} + +var validReceivedCloseCodes = map[int]bool{ + // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number + + CloseNormalClosure: true, + CloseGoingAway: true, + CloseProtocolError: true, + CloseUnsupportedData: true, + CloseNoStatusReceived: false, + CloseAbnormalClosure: false, + CloseInvalidFramePayloadData: true, + ClosePolicyViolation: true, + CloseMessageTooBig: true, + CloseMandatoryExtension: true, + CloseInternalServerErr: true, + CloseServiceRestart: true, + CloseTryAgainLater: true, + CloseTLSHandshake: false, +} + +func isValidReceivedCloseCode(code int) bool { + return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999) +} + +// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this +// interface. The type of the value stored in a pool is not specified. +type BufferPool interface { + // Get gets a value from the pool or returns nil if the pool is empty. + Get() interface{} + // Put adds a value to the pool. + Put(interface{}) +} + +// writePoolData is the type added to the write buffer pool. This wrapper is +// used to prevent applications from peeking at and depending on the values +// added to the pool. +type writePoolData struct{ buf []byte } + +// The Conn type represents a WebSocket connection. +type Conn struct { + conn net.Conn + isServer bool + subprotocol string + + // Write fields + mu chan bool // used as mutex to protect write to conn + writeBuf []byte // frame is constructed in this buffer. + writePool BufferPool + writeBufSize int + writeDeadline time.Time + writer io.WriteCloser // the current writer returned to the application + isWriting bool // for best-effort concurrent write detection + + writeErrMu sync.Mutex + writeErr error + + enableWriteCompression bool + compressionLevel int + newCompressionWriter func(io.WriteCloser, int) io.WriteCloser + + // Read fields + reader io.ReadCloser // the current reader returned to the application + readErr error + br *bufio.Reader + readRemaining int64 // bytes remaining in current frame. + readFinal bool // true the current message has more frames. + readLength int64 // Message size. + readLimit int64 // Maximum message size. + readMaskPos int + readMaskKey [4]byte + handlePong func(string) error + handlePing func(string) error + handleClose func(int, string) error + readErrCount int + messageReader *messageReader // the current low-level reader + + readDecompress bool // whether last read frame had RSV1 set + newDecompressionReader func(io.Reader) io.ReadCloser +} + +func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn { + + if br == nil { + if readBufferSize == 0 { + readBufferSize = defaultReadBufferSize + } else if readBufferSize < maxControlFramePayloadSize { + // must be large enough for control frame + readBufferSize = maxControlFramePayloadSize + } + br = bufio.NewReaderSize(conn, readBufferSize) + } + + if writeBufferSize <= 0 { + writeBufferSize = defaultWriteBufferSize + } + writeBufferSize += maxFrameHeaderSize + + if writeBuf == nil && writeBufferPool == nil { + writeBuf = make([]byte, writeBufferSize) + } + + mu := make(chan bool, 1) + mu <- true + c := &Conn{ + isServer: isServer, + br: br, + conn: conn, + mu: mu, + readFinal: true, + writeBuf: writeBuf, + writePool: writeBufferPool, + writeBufSize: writeBufferSize, + enableWriteCompression: true, + compressionLevel: defaultCompressionLevel, + } + c.SetCloseHandler(nil) + c.SetPingHandler(nil) + c.SetPongHandler(nil) + return c +} + +// Subprotocol returns the negotiated protocol for the connection. +func (c *Conn) Subprotocol() string { + return c.subprotocol +} + +// Close closes the underlying network connection without sending or waiting +// for a close message. +func (c *Conn) Close() error { + return c.conn.Close() +} + +// LocalAddr returns the local network address. +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the remote network address. +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// Write methods + +func (c *Conn) writeFatal(err error) error { + err = hideTempErr(err) + c.writeErrMu.Lock() + if c.writeErr == nil { + c.writeErr = err + } + c.writeErrMu.Unlock() + return err +} + +func (c *Conn) read(n int) ([]byte, error) { + p, err := c.br.Peek(n) + if err == io.EOF { + err = errUnexpectedEOF + } + c.br.Discard(len(p)) + return p, err +} + +func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error { + <-c.mu + defer func() { c.mu <- true }() + + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + if err != nil { + return err + } + + c.conn.SetWriteDeadline(deadline) + if len(buf1) == 0 { + _, err = c.conn.Write(buf0) + } else { + err = c.writeBufs(buf0, buf1) + } + if err != nil { + return c.writeFatal(err) + } + if frameType == CloseMessage { + c.writeFatal(ErrCloseSent) + } + return nil +} + +// WriteControl writes a control message with the given deadline. The allowed +// message types are CloseMessage, PingMessage and PongMessage. +func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error { + if !isControl(messageType) { + return errBadWriteOpCode + } + if len(data) > maxControlFramePayloadSize { + return errInvalidControlFrame + } + + b0 := byte(messageType) | finalBit + b1 := byte(len(data)) + if !c.isServer { + b1 |= maskBit + } + + buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize) + buf = append(buf, b0, b1) + + if c.isServer { + buf = append(buf, data...) + } else { + key := newMaskKey() + buf = append(buf, key[:]...) + buf = append(buf, data...) + maskBytes(key, 0, buf[6:]) + } + + d := time.Hour * 1000 + if !deadline.IsZero() { + d = deadline.Sub(time.Now()) + if d < 0 { + return errWriteTimeout + } + } + + timer := time.NewTimer(d) + select { + case <-c.mu: + timer.Stop() + case <-timer.C: + return errWriteTimeout + } + defer func() { c.mu <- true }() + + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + if err != nil { + return err + } + + c.conn.SetWriteDeadline(deadline) + _, err = c.conn.Write(buf) + if err != nil { + return c.writeFatal(err) + } + if messageType == CloseMessage { + c.writeFatal(ErrCloseSent) + } + return err +} + +func (c *Conn) prepWrite(messageType int) error { + // Close previous writer if not already closed by the application. It's + // probably better to return an error in this situation, but we cannot + // change this without breaking existing applications. + if c.writer != nil { + c.writer.Close() + c.writer = nil + } + + if !isControl(messageType) && !isData(messageType) { + return errBadWriteOpCode + } + + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + if err != nil { + return err + } + + if c.writeBuf == nil { + wpd, ok := c.writePool.Get().(writePoolData) + if ok { + c.writeBuf = wpd.buf + } else { + c.writeBuf = make([]byte, c.writeBufSize) + } + } + return nil +} + +// NextWriter returns a writer for the next message to send. The writer's Close +// method flushes the complete message to the network. +// +// There can be at most one open writer on a connection. NextWriter closes the +// previous writer if the application has not already done so. +// +// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and +// PongMessage) are supported. +func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { + if err := c.prepWrite(messageType); err != nil { + return nil, err + } + + mw := &messageWriter{ + c: c, + frameType: messageType, + pos: maxFrameHeaderSize, + } + c.writer = mw + if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { + w := c.newCompressionWriter(c.writer, c.compressionLevel) + mw.compress = true + c.writer = w + } + return c.writer, nil +} + +type messageWriter struct { + c *Conn + compress bool // whether next call to flushFrame should set RSV1 + pos int // end of data in writeBuf. + frameType int // type of the current frame. + err error +} + +func (w *messageWriter) fatal(err error) error { + if w.err != nil { + w.err = err + w.c.writer = nil + } + return err +} + +// flushFrame writes buffered data and extra as a frame to the network. The +// final argument indicates that this is the last frame in the message. +func (w *messageWriter) flushFrame(final bool, extra []byte) error { + c := w.c + length := w.pos - maxFrameHeaderSize + len(extra) + + // Check for invalid control frames. + if isControl(w.frameType) && + (!final || length > maxControlFramePayloadSize) { + return w.fatal(errInvalidControlFrame) + } + + b0 := byte(w.frameType) + if final { + b0 |= finalBit + } + if w.compress { + b0 |= rsv1Bit + } + w.compress = false + + b1 := byte(0) + if !c.isServer { + b1 |= maskBit + } + + // Assume that the frame starts at beginning of c.writeBuf. + framePos := 0 + if c.isServer { + // Adjust up if mask not included in the header. + framePos = 4 + } + + switch { + case length >= 65536: + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | 127 + binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length)) + case length > 125: + framePos += 6 + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | 126 + binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length)) + default: + framePos += 8 + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | byte(length) + } + + if !c.isServer { + key := newMaskKey() + copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) + maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) + if len(extra) > 0 { + return c.writeFatal(errors.New("websocket: internal error, extra used in client mode")) + } + } + + // Write the buffers to the connection with best-effort detection of + // concurrent writes. See the concurrency section in the package + // documentation for more info. + + if c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = true + + err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra) + + if !c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = false + + if err != nil { + return w.fatal(err) + } + + if final { + c.writer = nil + if c.writePool != nil { + c.writePool.Put(writePoolData{buf: c.writeBuf}) + c.writeBuf = nil + } + return nil + } + + // Setup for next frame. + w.pos = maxFrameHeaderSize + w.frameType = continuationFrame + return nil +} + +func (w *messageWriter) ncopy(max int) (int, error) { + n := len(w.c.writeBuf) - w.pos + if n <= 0 { + if err := w.flushFrame(false, nil); err != nil { + return 0, err + } + n = len(w.c.writeBuf) - w.pos + } + if n > max { + n = max + } + return n, nil +} + +func (w *messageWriter) Write(p []byte) (int, error) { + if w.err != nil { + return 0, w.err + } + + if len(p) > 2*len(w.c.writeBuf) && w.c.isServer { + // Don't buffer large messages. + err := w.flushFrame(false, p) + if err != nil { + return 0, err + } + return len(p), nil + } + + nn := len(p) + for len(p) > 0 { + n, err := w.ncopy(len(p)) + if err != nil { + return 0, err + } + copy(w.c.writeBuf[w.pos:], p[:n]) + w.pos += n + p = p[n:] + } + return nn, nil +} + +func (w *messageWriter) WriteString(p string) (int, error) { + if w.err != nil { + return 0, w.err + } + + nn := len(p) + for len(p) > 0 { + n, err := w.ncopy(len(p)) + if err != nil { + return 0, err + } + copy(w.c.writeBuf[w.pos:], p[:n]) + w.pos += n + p = p[n:] + } + return nn, nil +} + +func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { + if w.err != nil { + return 0, w.err + } + for { + if w.pos == len(w.c.writeBuf) { + err = w.flushFrame(false, nil) + if err != nil { + break + } + } + var n int + n, err = r.Read(w.c.writeBuf[w.pos:]) + w.pos += n + nn += int64(n) + if err != nil { + if err == io.EOF { + err = nil + } + break + } + } + return nn, err +} + +func (w *messageWriter) Close() error { + if w.err != nil { + return w.err + } + if err := w.flushFrame(true, nil); err != nil { + return err + } + w.err = errWriteClosed + return nil +} + +// WritePreparedMessage writes prepared message into connection. +func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error { + frameType, frameData, err := pm.frame(prepareKey{ + isServer: c.isServer, + compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType), + compressionLevel: c.compressionLevel, + }) + if err != nil { + return err + } + if c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = true + err = c.write(frameType, c.writeDeadline, frameData, nil) + if !c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = false + return err +} + +// WriteMessage is a helper method for getting a writer using NextWriter, +// writing the message and closing the writer. +func (c *Conn) WriteMessage(messageType int, data []byte) error { + + if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { + // Fast path with no allocations and single frame. + + if err := c.prepWrite(messageType); err != nil { + return err + } + mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize} + n := copy(c.writeBuf[mw.pos:], data) + mw.pos += n + data = data[n:] + return mw.flushFrame(true, data) + } + + w, err := c.NextWriter(messageType) + if err != nil { + return err + } + if _, err = w.Write(data); err != nil { + return err + } + return w.Close() +} + +// SetWriteDeadline sets the write deadline on the underlying network +// connection. After a write has timed out, the websocket state is corrupt and +// all future writes will return an error. A zero value for t means writes will +// not time out. +func (c *Conn) SetWriteDeadline(t time.Time) error { + c.writeDeadline = t + return nil +} + +// Read methods + +func (c *Conn) advanceFrame() (int, error) { + // 1. Skip remainder of previous frame. + + if c.readRemaining > 0 { + if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil { + return noFrame, err + } + } + + // 2. Read and parse first two bytes of frame header. + + p, err := c.read(2) + if err != nil { + return noFrame, err + } + + final := p[0]&finalBit != 0 + frameType := int(p[0] & 0xf) + mask := p[1]&maskBit != 0 + c.readRemaining = int64(p[1] & 0x7f) + + c.readDecompress = false + if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 { + c.readDecompress = true + p[0] &^= rsv1Bit + } + + if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 { + return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16)) + } + + switch frameType { + case CloseMessage, PingMessage, PongMessage: + if c.readRemaining > maxControlFramePayloadSize { + return noFrame, c.handleProtocolError("control frame length > 125") + } + if !final { + return noFrame, c.handleProtocolError("control frame not final") + } + case TextMessage, BinaryMessage: + if !c.readFinal { + return noFrame, c.handleProtocolError("message start before final message frame") + } + c.readFinal = final + case continuationFrame: + if c.readFinal { + return noFrame, c.handleProtocolError("continuation after final message frame") + } + c.readFinal = final + default: + return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType)) + } + + // 3. Read and parse frame length. + + switch c.readRemaining { + case 126: + p, err := c.read(2) + if err != nil { + return noFrame, err + } + c.readRemaining = int64(binary.BigEndian.Uint16(p)) + case 127: + p, err := c.read(8) + if err != nil { + return noFrame, err + } + c.readRemaining = int64(binary.BigEndian.Uint64(p)) + } + + // 4. Handle frame masking. + + if mask != c.isServer { + return noFrame, c.handleProtocolError("incorrect mask flag") + } + + if mask { + c.readMaskPos = 0 + p, err := c.read(len(c.readMaskKey)) + if err != nil { + return noFrame, err + } + copy(c.readMaskKey[:], p) + } + + // 5. For text and binary messages, enforce read limit and return. + + if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { + + c.readLength += c.readRemaining + if c.readLimit > 0 && c.readLength > c.readLimit { + c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) + return noFrame, ErrReadLimit + } + + return frameType, nil + } + + // 6. Read control frame payload. + + var payload []byte + if c.readRemaining > 0 { + payload, err = c.read(int(c.readRemaining)) + c.readRemaining = 0 + if err != nil { + return noFrame, err + } + if c.isServer { + maskBytes(c.readMaskKey, 0, payload) + } + } + + // 7. Process control frame payload. + + switch frameType { + case PongMessage: + if err := c.handlePong(string(payload)); err != nil { + return noFrame, err + } + case PingMessage: + if err := c.handlePing(string(payload)); err != nil { + return noFrame, err + } + case CloseMessage: + closeCode := CloseNoStatusReceived + closeText := "" + if len(payload) >= 2 { + closeCode = int(binary.BigEndian.Uint16(payload)) + if !isValidReceivedCloseCode(closeCode) { + return noFrame, c.handleProtocolError("invalid close code") + } + closeText = string(payload[2:]) + if !utf8.ValidString(closeText) { + return noFrame, c.handleProtocolError("invalid utf8 payload in close frame") + } + } + if err := c.handleClose(closeCode, closeText); err != nil { + return noFrame, err + } + return noFrame, &CloseError{Code: closeCode, Text: closeText} + } + + return frameType, nil +} + +func (c *Conn) handleProtocolError(message string) error { + c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait)) + return errors.New("websocket: " + message) +} + +// NextReader returns the next data message received from the peer. The +// returned messageType is either TextMessage or BinaryMessage. +// +// There can be at most one open reader on a connection. NextReader discards +// the previous message if the application has not already consumed it. +// +// Applications must break out of the application's read loop when this method +// returns a non-nil error value. Errors returned from this method are +// permanent. Once this method returns a non-nil error, all subsequent calls to +// this method return the same error. +func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { + // Close previous reader, only relevant for decompression. + if c.reader != nil { + c.reader.Close() + c.reader = nil + } + + c.messageReader = nil + c.readLength = 0 + + for c.readErr == nil { + frameType, err := c.advanceFrame() + if err != nil { + c.readErr = hideTempErr(err) + break + } + if frameType == TextMessage || frameType == BinaryMessage { + c.messageReader = &messageReader{c} + c.reader = c.messageReader + if c.readDecompress { + c.reader = c.newDecompressionReader(c.reader) + } + return frameType, c.reader, nil + } + } + + // Applications that do handle the error returned from this method spin in + // tight loop on connection failure. To help application developers detect + // this error, panic on repeated reads to the failed connection. + c.readErrCount++ + if c.readErrCount >= 1000 { + panic("repeated read on failed websocket connection") + } + + return noFrame, nil, c.readErr +} + +type messageReader struct{ c *Conn } + +func (r *messageReader) Read(b []byte) (int, error) { + c := r.c + if c.messageReader != r { + return 0, io.EOF + } + + for c.readErr == nil { + + if c.readRemaining > 0 { + if int64(len(b)) > c.readRemaining { + b = b[:c.readRemaining] + } + n, err := c.br.Read(b) + c.readErr = hideTempErr(err) + if c.isServer { + c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) + } + c.readRemaining -= int64(n) + if c.readRemaining > 0 && c.readErr == io.EOF { + c.readErr = errUnexpectedEOF + } + return n, c.readErr + } + + if c.readFinal { + c.messageReader = nil + return 0, io.EOF + } + + frameType, err := c.advanceFrame() + switch { + case err != nil: + c.readErr = hideTempErr(err) + case frameType == TextMessage || frameType == BinaryMessage: + c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader") + } + } + + err := c.readErr + if err == io.EOF && c.messageReader == r { + err = errUnexpectedEOF + } + return 0, err +} + +func (r *messageReader) Close() error { + return nil +} + +// ReadMessage is a helper method for getting a reader using NextReader and +// reading from that reader to a buffer. +func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { + var r io.Reader + messageType, r, err = c.NextReader() + if err != nil { + return messageType, nil, err + } + p, err = ioutil.ReadAll(r) + return messageType, p, err +} + +// SetReadDeadline sets the read deadline on the underlying network connection. +// After a read has timed out, the websocket connection state is corrupt and +// all future reads will return an error. A zero value for t means reads will +// not time out. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetReadLimit sets the maximum size for a message read from the peer. If a +// message exceeds the limit, the connection sends a close message to the peer +// and returns ErrReadLimit to the application. +func (c *Conn) SetReadLimit(limit int64) { + c.readLimit = limit +} + +// CloseHandler returns the current close handler +func (c *Conn) CloseHandler() func(code int, text string) error { + return c.handleClose +} + +// SetCloseHandler sets the handler for close messages received from the peer. +// The code argument to h is the received close code or CloseNoStatusReceived +// if the close message is empty. The default close handler sends a close +// message back to the peer. +// +// The handler function is called from the NextReader, ReadMessage and message +// reader Read methods. The application must read the connection to process +// close messages as described in the section on Control Messages above. +// +// The connection read methods return a CloseError when a close message is +// received. Most applications should handle close messages as part of their +// normal error handling. Applications should only set a close handler when the +// application must perform some action before sending a close message back to +// the peer. +func (c *Conn) SetCloseHandler(h func(code int, text string) error) { + if h == nil { + h = func(code int, text string) error { + message := FormatCloseMessage(code, "") + c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) + return nil + } + } + c.handleClose = h +} + +// PingHandler returns the current ping handler +func (c *Conn) PingHandler() func(appData string) error { + return c.handlePing +} + +// SetPingHandler sets the handler for ping messages received from the peer. +// The appData argument to h is the PING message application data. The default +// ping handler sends a pong to the peer. +// +// The handler function is called from the NextReader, ReadMessage and message +// reader Read methods. The application must read the connection to process +// ping messages as described in the section on Control Messages above. +func (c *Conn) SetPingHandler(h func(appData string) error) { + if h == nil { + h = func(message string) error { + err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) + if err == ErrCloseSent { + return nil + } else if e, ok := err.(net.Error); ok && e.Temporary() { + return nil + } + return err + } + } + c.handlePing = h +} + +// PongHandler returns the current pong handler +func (c *Conn) PongHandler() func(appData string) error { + return c.handlePong +} + +// SetPongHandler sets the handler for pong messages received from the peer. +// The appData argument to h is the PONG message application data. The default +// pong handler does nothing. +// +// The handler function is called from the NextReader, ReadMessage and message +// reader Read methods. The application must read the connection to process +// pong messages as described in the section on Control Messages above. +func (c *Conn) SetPongHandler(h func(appData string) error) { + if h == nil { + h = func(string) error { return nil } + } + c.handlePong = h +} + +// UnderlyingConn returns the internal net.Conn. This can be used to further +// modifications to connection specific flags. +func (c *Conn) UnderlyingConn() net.Conn { + return c.conn +} + +// EnableWriteCompression enables and disables write compression of +// subsequent text and binary messages. This function is a noop if +// compression was not negotiated with the peer. +func (c *Conn) EnableWriteCompression(enable bool) { + c.enableWriteCompression = enable +} + +// SetCompressionLevel sets the flate compression level for subsequent text and +// binary messages. This function is a noop if compression was not negotiated +// with the peer. See the compress/flate package for a description of +// compression levels. +func (c *Conn) SetCompressionLevel(level int) error { + if !isValidCompressionLevel(level) { + return errors.New("websocket: invalid compression level") + } + c.compressionLevel = level + return nil +} + +// FormatCloseMessage formats closeCode and text as a WebSocket close message. +// An empty message is returned for code CloseNoStatusReceived. +func FormatCloseMessage(closeCode int, text string) []byte { + if closeCode == CloseNoStatusReceived { + // Return empty message because it's illegal to send + // CloseNoStatusReceived. Return non-nil value in case application + // checks for nil. + return []byte{} + } + buf := make([]byte, 2+len(text)) + binary.BigEndian.PutUint16(buf, uint16(closeCode)) + copy(buf[2:], text) + return buf +} diff --git a/vendor/github.com/gorilla/websocket/conn_write.go b/vendor/github.com/gorilla/websocket/conn_write.go new file mode 100644 index 0000000..a509a21 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/conn_write.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Gorilla WebSocket 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.8 + +package websocket + +import "net" + +func (c *Conn) writeBufs(bufs ...[]byte) error { + b := net.Buffers(bufs) + _, err := b.WriteTo(c.conn) + return err +} diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go new file mode 100644 index 0000000..37edaff --- /dev/null +++ b/vendor/github.com/gorilla/websocket/conn_write_legacy.go @@ -0,0 +1,18 @@ +// Copyright 2016 The Gorilla WebSocket 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.8 + +package websocket + +func (c *Conn) writeBufs(bufs ...[]byte) error { + for _, buf := range bufs { + if len(buf) > 0 { + if _, err := c.conn.Write(buf); err != nil { + return err + } + } + } + return nil +} diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go new file mode 100644 index 0000000..dcce1a6 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/doc.go @@ -0,0 +1,180 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket implements the WebSocket protocol defined in RFC 6455. +// +// Overview +// +// The Conn type represents a WebSocket connection. A server application calls +// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn: +// +// var upgrader = websocket.Upgrader{ +// ReadBufferSize: 1024, +// WriteBufferSize: 1024, +// } +// +// func handler(w http.ResponseWriter, r *http.Request) { +// conn, err := upgrader.Upgrade(w, r, nil) +// if err != nil { +// log.Println(err) +// return +// } +// ... Use conn to send and receive messages. +// } +// +// Call the connection's WriteMessage and ReadMessage methods to send and +// receive messages as a slice of bytes. This snippet of code shows how to echo +// messages using these methods: +// +// for { +// messageType, p, err := conn.ReadMessage() +// if err != nil { +// log.Println(err) +// return +// } +// if err := conn.WriteMessage(messageType, p); err != nil { +// log.Println(err) +// return +// } +// } +// +// In above snippet of code, p is a []byte and messageType is an int with value +// websocket.BinaryMessage or websocket.TextMessage. +// +// An application can also send and receive messages using the io.WriteCloser +// and io.Reader interfaces. To send a message, call the connection NextWriter +// method to get an io.WriteCloser, write the message to the writer and close +// the writer when done. To receive a message, call the connection NextReader +// method to get an io.Reader and read until io.EOF is returned. This snippet +// shows how to echo messages using the NextWriter and NextReader methods: +// +// for { +// messageType, r, err := conn.NextReader() +// if err != nil { +// return +// } +// w, err := conn.NextWriter(messageType) +// if err != nil { +// return err +// } +// if _, err := io.Copy(w, r); err != nil { +// return err +// } +// if err := w.Close(); err != nil { +// return err +// } +// } +// +// Data Messages +// +// The WebSocket protocol distinguishes between text and binary data messages. +// Text messages are interpreted as UTF-8 encoded text. The interpretation of +// binary messages is left to the application. +// +// This package uses the TextMessage and BinaryMessage integer constants to +// identify the two data message types. The ReadMessage and NextReader methods +// return the type of the received message. The messageType argument to the +// WriteMessage and NextWriter methods specifies the type of a sent message. +// +// It is the application's responsibility to ensure that text messages are +// valid UTF-8 encoded text. +// +// Control Messages +// +// The WebSocket protocol defines three types of control messages: close, ping +// and pong. Call the connection WriteControl, WriteMessage or NextWriter +// methods to send a control message to the peer. +// +// Connections handle received close messages by calling the handler function +// set with the SetCloseHandler method and by returning a *CloseError from the +// NextReader, ReadMessage or the message Read method. The default close +// handler sends a close message to the peer. +// +// Connections handle received ping messages by calling the handler function +// set with the SetPingHandler method. The default ping handler sends a pong +// message to the peer. +// +// Connections handle received pong messages by calling the handler function +// set with the SetPongHandler method. The default pong handler does nothing. +// If an application sends ping messages, then the application should set a +// pong handler to receive the corresponding pong. +// +// The control message handler functions are called from the NextReader, +// ReadMessage and message reader Read methods. The default close and ping +// handlers can block these methods for a short time when the handler writes to +// the connection. +// +// The application must read the connection to process close, ping and pong +// messages sent from the peer. If the application is not otherwise interested +// in messages from the peer, then the application should start a goroutine to +// read and discard messages from the peer. A simple example is: +// +// func readLoop(c *websocket.Conn) { +// for { +// if _, _, err := c.NextReader(); err != nil { +// c.Close() +// break +// } +// } +// } +// +// Concurrency +// +// Connections support one concurrent reader and one concurrent writer. +// +// Applications are responsible for ensuring that no more than one goroutine +// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, +// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and +// that no more than one goroutine calls the read methods (NextReader, +// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) +// concurrently. +// +// The Close and WriteControl methods can be called concurrently with all other +// methods. +// +// Origin Considerations +// +// Web browsers allow Javascript applications to open a WebSocket connection to +// any host. It's up to the server to enforce an origin policy using the Origin +// request header sent by the browser. +// +// The Upgrader calls the function specified in the CheckOrigin field to check +// the origin. If the CheckOrigin function returns false, then the Upgrade +// method fails the WebSocket handshake with HTTP status 403. +// +// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail +// the handshake if the Origin request header is present and the Origin host is +// not equal to the Host request header. +// +// The deprecated package-level Upgrade function does not perform origin +// checking. The application is responsible for checking the Origin header +// before calling the Upgrade function. +// +// Compression EXPERIMENTAL +// +// Per message compression extensions (RFC 7692) are experimentally supported +// by this package in a limited capacity. Setting the EnableCompression option +// to true in Dialer or Upgrader will attempt to negotiate per message deflate +// support. +// +// var upgrader = websocket.Upgrader{ +// EnableCompression: true, +// } +// +// If compression was successfully negotiated with the connection's peer, any +// message received in compressed form will be automatically decompressed. +// All Read methods will return uncompressed bytes. +// +// Per message compression of messages written to a connection can be enabled +// or disabled by calling the corresponding Conn method: +// +// conn.EnableWriteCompression(false) +// +// Currently this package does not support compression with "context takeover". +// This means that messages must be compressed and decompressed in isolation, +// without retaining sliding window or dictionary state across messages. For +// more details refer to RFC 7692. +// +// Use of compression is experimental and may result in decreased performance. +package websocket diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go new file mode 100644 index 0000000..dc2c1f6 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/json.go @@ -0,0 +1,60 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket + +import ( + "encoding/json" + "io" +) + +// WriteJSON writes the JSON encoding of v as a message. +// +// Deprecated: Use c.WriteJSON instead. +func WriteJSON(c *Conn, v interface{}) error { + return c.WriteJSON(v) +} + +// WriteJSON writes the JSON encoding of v as a message. +// +// See the documentation for encoding/json Marshal for details about the +// conversion of Go values to JSON. +func (c *Conn) WriteJSON(v interface{}) error { + w, err := c.NextWriter(TextMessage) + if err != nil { + return err + } + err1 := json.NewEncoder(w).Encode(v) + err2 := w.Close() + if err1 != nil { + return err1 + } + return err2 +} + +// ReadJSON reads the next JSON-encoded message from the connection and stores +// it in the value pointed to by v. +// +// Deprecated: Use c.ReadJSON instead. +func ReadJSON(c *Conn, v interface{}) error { + return c.ReadJSON(v) +} + +// ReadJSON reads the next JSON-encoded message from the connection and stores +// it in the value pointed to by v. +// +// See the documentation for the encoding/json Unmarshal function for details +// about the conversion of JSON to a Go value. +func (c *Conn) ReadJSON(v interface{}) error { + _, r, err := c.NextReader() + if err != nil { + return err + } + err = json.NewDecoder(r).Decode(v) + if err == io.EOF { + // One value is expected in the message. + err = io.ErrUnexpectedEOF + } + return err +} diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go new file mode 100644 index 0000000..577fce9 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/mask.go @@ -0,0 +1,54 @@ +// Copyright 2016 The Gorilla WebSocket 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 !appengine + +package websocket + +import "unsafe" + +const wordSize = int(unsafe.Sizeof(uintptr(0))) + +func maskBytes(key [4]byte, pos int, b []byte) int { + // Mask one byte at a time for small buffers. + if len(b) < 2*wordSize { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 + } + + // Mask one byte at a time to word boundary. + if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { + n = wordSize - n + for i := range b[:n] { + b[i] ^= key[pos&3] + pos++ + } + b = b[n:] + } + + // Create aligned word size key. + var k [wordSize]byte + for i := range k { + k[i] = key[(pos+i)&3] + } + kw := *(*uintptr)(unsafe.Pointer(&k)) + + // Mask one word at a time. + n := (len(b) / wordSize) * wordSize + for i := 0; i < n; i += wordSize { + *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw + } + + // Mask one byte at a time for remaining bytes. + b = b[n:] + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + + return pos & 3 +} diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go new file mode 100644 index 0000000..2aac060 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/mask_safe.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Gorilla WebSocket 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 appengine + +package websocket + +func maskBytes(key [4]byte, pos int, b []byte) int { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 +} diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go new file mode 100644 index 0000000..74ec565 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/prepared.go @@ -0,0 +1,102 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "bytes" + "net" + "sync" + "time" +) + +// PreparedMessage caches on the wire representations of a message payload. +// Use PreparedMessage to efficiently send a message payload to multiple +// connections. PreparedMessage is especially useful when compression is used +// because the CPU and memory expensive compression operation can be executed +// once for a given set of compression options. +type PreparedMessage struct { + messageType int + data []byte + mu sync.Mutex + frames map[prepareKey]*preparedFrame +} + +// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. +type prepareKey struct { + isServer bool + compress bool + compressionLevel int +} + +// preparedFrame contains data in wire representation. +type preparedFrame struct { + once sync.Once + data []byte +} + +// NewPreparedMessage returns an initialized PreparedMessage. You can then send +// it to connection using WritePreparedMessage method. Valid wire +// representation will be calculated lazily only once for a set of current +// connection options. +func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { + pm := &PreparedMessage{ + messageType: messageType, + frames: make(map[prepareKey]*preparedFrame), + data: data, + } + + // Prepare a plain server frame. + _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) + if err != nil { + return nil, err + } + + // To protect against caller modifying the data argument, remember the data + // copied to the plain server frame. + pm.data = frameData[len(frameData)-len(data):] + return pm, nil +} + +func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { + pm.mu.Lock() + frame, ok := pm.frames[key] + if !ok { + frame = &preparedFrame{} + pm.frames[key] = frame + } + pm.mu.Unlock() + + var err error + frame.once.Do(func() { + // Prepare a frame using a 'fake' connection. + // TODO: Refactor code in conn.go to allow more direct construction of + // the frame. + mu := make(chan bool, 1) + mu <- true + var nc prepareConn + c := &Conn{ + conn: &nc, + mu: mu, + isServer: key.isServer, + compressionLevel: key.compressionLevel, + enableWriteCompression: true, + writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), + } + if key.compress { + c.newCompressionWriter = compressNoContextTakeover + } + err = c.WriteMessage(pm.messageType, pm.data) + frame.data = nc.buf.Bytes() + }) + return pm.messageType, frame.data, err +} + +type prepareConn struct { + buf bytes.Buffer + net.Conn +} + +func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) } +func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go new file mode 100644 index 0000000..bf2478e --- /dev/null +++ b/vendor/github.com/gorilla/websocket/proxy.go @@ -0,0 +1,77 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "bufio" + "encoding/base64" + "errors" + "net" + "net/http" + "net/url" + "strings" +) + +type netDialerFunc func(network, addr string) (net.Conn, error) + +func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { + return fn(network, addr) +} + +func init() { + proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { + return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil + }) +} + +type httpProxyDialer struct { + proxyURL *url.URL + fowardDial func(network, addr string) (net.Conn, error) +} + +func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { + hostPort, _ := hostPortNoPort(hpd.proxyURL) + conn, err := hpd.fowardDial(network, hostPort) + if err != nil { + return nil, err + } + + connectHeader := make(http.Header) + if user := hpd.proxyURL.User; user != nil { + proxyUser := user.Username() + if proxyPassword, passwordSet := user.Password(); passwordSet { + credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) + connectHeader.Set("Proxy-Authorization", "Basic "+credential) + } + } + + connectReq := &http.Request{ + Method: "CONNECT", + URL: &url.URL{Opaque: addr}, + Host: addr, + Header: connectHeader, + } + + if err := connectReq.Write(conn); err != nil { + conn.Close() + return nil, err + } + + // Read response. It's OK to use and discard buffered reader here becaue + // the remote server does not speak until spoken to. + br := bufio.NewReader(conn) + resp, err := http.ReadResponse(br, connectReq) + if err != nil { + conn.Close() + return nil, err + } + + if resp.StatusCode != 200 { + conn.Close() + f := strings.SplitN(resp.Status, " ", 2) + return nil, errors.New(f[1]) + } + return conn, nil +} diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go new file mode 100644 index 0000000..a761824 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/server.go @@ -0,0 +1,363 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket + +import ( + "bufio" + "errors" + "io" + "net/http" + "net/url" + "strings" + "time" +) + +// HandshakeError describes an error with the handshake from the peer. +type HandshakeError struct { + message string +} + +func (e HandshakeError) Error() string { return e.message } + +// Upgrader specifies parameters for upgrading an HTTP connection to a +// WebSocket connection. +type Upgrader struct { + // HandshakeTimeout specifies the duration for the handshake to complete. + HandshakeTimeout time.Duration + + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then buffers allocated by the HTTP server are used. The + // I/O buffer sizes do not limit the size of the messages that can be sent + // or received. + ReadBufferSize, WriteBufferSize int + + // WriteBufferPool is a pool of buffers for write operations. If the value + // is not set, then write buffers are allocated to the connection for the + // lifetime of the connection. + // + // A pool is most useful when the application has a modest volume of writes + // across a large number of connections. + // + // Applications should use a single pool for each unique value of + // WriteBufferSize. + WriteBufferPool BufferPool + + // Subprotocols specifies the server's supported protocols in order of + // preference. If this field is not nil, then the Upgrade method negotiates a + // subprotocol by selecting the first match in this list with a protocol + // requested by the client. If there's no match, then no protocol is + // negotiated (the Sec-Websocket-Protocol header is not included in the + // handshake response). + Subprotocols []string + + // Error specifies the function for generating HTTP error responses. If Error + // is nil, then http.Error is used to generate the HTTP response. + Error func(w http.ResponseWriter, r *http.Request, status int, reason error) + + // CheckOrigin returns true if the request Origin header is acceptable. If + // CheckOrigin is nil, then a safe default is used: return false if the + // Origin request header is present and the origin host is not equal to + // request Host header. + // + // A CheckOrigin function should carefully validate the request origin to + // prevent cross-site request forgery. + CheckOrigin func(r *http.Request) bool + + // EnableCompression specify if the server should attempt to negotiate per + // message compression (RFC 7692). Setting this value to true does not + // guarantee that compression will be supported. Currently only "no context + // takeover" modes are supported. + EnableCompression bool +} + +func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { + err := HandshakeError{reason} + if u.Error != nil { + u.Error(w, r, status, err) + } else { + w.Header().Set("Sec-Websocket-Version", "13") + http.Error(w, http.StatusText(status), status) + } + return nil, err +} + +// checkSameOrigin returns true if the origin is not set or is equal to the request host. +func checkSameOrigin(r *http.Request) bool { + origin := r.Header["Origin"] + if len(origin) == 0 { + return true + } + u, err := url.Parse(origin[0]) + if err != nil { + return false + } + return equalASCIIFold(u.Host, r.Host) +} + +func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { + if u.Subprotocols != nil { + clientProtocols := Subprotocols(r) + for _, serverProtocol := range u.Subprotocols { + for _, clientProtocol := range clientProtocols { + if clientProtocol == serverProtocol { + return clientProtocol + } + } + } + } else if responseHeader != nil { + return responseHeader.Get("Sec-Websocket-Protocol") + } + return "" +} + +// Upgrade upgrades the HTTP server connection to the WebSocket protocol. +// +// The responseHeader is included in the response to the client's upgrade +// request. Use the responseHeader to specify cookies (Set-Cookie) and the +// application negotiated subprotocol (Sec-WebSocket-Protocol). +// +// If the upgrade fails, then Upgrade replies to the client with an HTTP error +// response. +func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { + const badHandshake = "websocket: the client is not using the websocket protocol: " + + if !tokenListContainsValue(r.Header, "Connection", "upgrade") { + return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header") + } + + if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { + return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header") + } + + if r.Method != "GET" { + return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET") + } + + if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { + return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") + } + + if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { + return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported") + } + + checkOrigin := u.CheckOrigin + if checkOrigin == nil { + checkOrigin = checkSameOrigin + } + if !checkOrigin(r) { + return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin") + } + + challengeKey := r.Header.Get("Sec-Websocket-Key") + if challengeKey == "" { + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank") + } + + subprotocol := u.selectSubprotocol(r, responseHeader) + + // Negotiate PMCE + var compress bool + if u.EnableCompression { + for _, ext := range parseExtensions(r.Header) { + if ext[""] != "permessage-deflate" { + continue + } + compress = true + break + } + } + + h, ok := w.(http.Hijacker) + if !ok { + return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") + } + var brw *bufio.ReadWriter + netConn, brw, err := h.Hijack() + if err != nil { + return u.returnError(w, r, http.StatusInternalServerError, err.Error()) + } + + if brw.Reader.Buffered() > 0 { + netConn.Close() + return nil, errors.New("websocket: client sent data before handshake is complete") + } + + var br *bufio.Reader + if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 { + // Reuse hijacked buffered reader as connection reader. + br = brw.Reader + } + + buf := bufioWriterBuffer(netConn, brw.Writer) + + var writeBuf []byte + if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 { + // Reuse hijacked write buffer as connection buffer. + writeBuf = buf + } + + c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf) + c.subprotocol = subprotocol + + if compress { + c.newCompressionWriter = compressNoContextTakeover + c.newDecompressionReader = decompressNoContextTakeover + } + + // Use larger of hijacked buffer and connection write buffer for header. + p := buf + if len(c.writeBuf) > len(p) { + p = c.writeBuf + } + p = p[:0] + + p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) + p = append(p, computeAcceptKey(challengeKey)...) + p = append(p, "\r\n"...) + if c.subprotocol != "" { + p = append(p, "Sec-WebSocket-Protocol: "...) + p = append(p, c.subprotocol...) + p = append(p, "\r\n"...) + } + if compress { + p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) + } + for k, vs := range responseHeader { + if k == "Sec-Websocket-Protocol" { + continue + } + for _, v := range vs { + p = append(p, k...) + p = append(p, ": "...) + for i := 0; i < len(v); i++ { + b := v[i] + if b <= 31 { + // prevent response splitting. + b = ' ' + } + p = append(p, b) + } + p = append(p, "\r\n"...) + } + } + p = append(p, "\r\n"...) + + // Clear deadlines set by HTTP server. + netConn.SetDeadline(time.Time{}) + + if u.HandshakeTimeout > 0 { + netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) + } + if _, err = netConn.Write(p); err != nil { + netConn.Close() + return nil, err + } + if u.HandshakeTimeout > 0 { + netConn.SetWriteDeadline(time.Time{}) + } + + return c, nil +} + +// Upgrade upgrades the HTTP server connection to the WebSocket protocol. +// +// Deprecated: Use websocket.Upgrader instead. +// +// Upgrade does not perform origin checking. The application is responsible for +// checking the Origin header before calling Upgrade. An example implementation +// of the same origin policy check is: +// +// if req.Header.Get("Origin") != "http://"+req.Host { +// http.Error(w, "Origin not allowed", http.StatusForbidden) +// return +// } +// +// If the endpoint supports subprotocols, then the application is responsible +// for negotiating the protocol used on the connection. Use the Subprotocols() +// function to get the subprotocols requested by the client. Use the +// Sec-Websocket-Protocol response header to specify the subprotocol selected +// by the application. +// +// The responseHeader is included in the response to the client's upgrade +// request. Use the responseHeader to specify cookies (Set-Cookie) and the +// negotiated subprotocol (Sec-Websocket-Protocol). +// +// The connection buffers IO to the underlying network connection. The +// readBufSize and writeBufSize parameters specify the size of the buffers to +// use. Messages can be larger than the buffers. +// +// If the request is not a valid WebSocket handshake, then Upgrade returns an +// error of type HandshakeError. Applications should handle this error by +// replying to the client with an HTTP error response. +func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { + u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize} + u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) { + // don't return errors to maintain backwards compatibility + } + u.CheckOrigin = func(r *http.Request) bool { + // allow all connections by default + return true + } + return u.Upgrade(w, r, responseHeader) +} + +// Subprotocols returns the subprotocols requested by the client in the +// Sec-Websocket-Protocol header. +func Subprotocols(r *http.Request) []string { + h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol")) + if h == "" { + return nil + } + protocols := strings.Split(h, ",") + for i := range protocols { + protocols[i] = strings.TrimSpace(protocols[i]) + } + return protocols +} + +// IsWebSocketUpgrade returns true if the client requested upgrade to the +// WebSocket protocol. +func IsWebSocketUpgrade(r *http.Request) bool { + return tokenListContainsValue(r.Header, "Connection", "upgrade") && + tokenListContainsValue(r.Header, "Upgrade", "websocket") +} + +// bufioReaderSize size returns the size of a bufio.Reader. +func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int { + // This code assumes that peek on a reset reader returns + // bufio.Reader.buf[:0]. + // TODO: Use bufio.Reader.Size() after Go 1.10 + br.Reset(originalReader) + if p, err := br.Peek(0); err == nil { + return cap(p) + } + return 0 +} + +// writeHook is an io.Writer that records the last slice passed to it vio +// io.Writer.Write. +type writeHook struct { + p []byte +} + +func (wh *writeHook) Write(p []byte) (int, error) { + wh.p = p + return len(p), nil +} + +// bufioWriterBuffer grabs the buffer from a bufio.Writer. +func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte { + // This code assumes that bufio.Writer.buf[:1] is passed to the + // bufio.Writer's underlying writer. + var wh writeHook + bw.Reset(&wh) + bw.WriteByte(0) + bw.Flush() + + bw.Reset(originalWriter) + + return wh.p[:cap(wh.p)] +} diff --git a/vendor/github.com/gorilla/websocket/trace.go b/vendor/github.com/gorilla/websocket/trace.go new file mode 100644 index 0000000..834f122 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/trace.go @@ -0,0 +1,19 @@ +// +build go1.8 + +package websocket + +import ( + "crypto/tls" + "net/http/httptrace" +) + +func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { + if trace.TLSHandshakeStart != nil { + trace.TLSHandshakeStart() + } + err := doHandshake(tlsConn, cfg) + if trace.TLSHandshakeDone != nil { + trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) + } + return err +} diff --git a/vendor/github.com/gorilla/websocket/trace_17.go b/vendor/github.com/gorilla/websocket/trace_17.go new file mode 100644 index 0000000..77d05a0 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/trace_17.go @@ -0,0 +1,12 @@ +// +build !go1.8 + +package websocket + +import ( + "crypto/tls" + "net/http/httptrace" +) + +func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { + return doHandshake(tlsConn, cfg) +} diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go new file mode 100644 index 0000000..354001e --- /dev/null +++ b/vendor/github.com/gorilla/websocket/util.go @@ -0,0 +1,237 @@ +// Copyright 2013 The Gorilla WebSocket 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 websocket + +import ( + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "io" + "net/http" + "strings" + "unicode/utf8" +) + +var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + +func computeAcceptKey(challengeKey string) string { + h := sha1.New() + h.Write([]byte(challengeKey)) + h.Write(keyGUID) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func generateChallengeKey() (string, error) { + p := make([]byte, 16) + if _, err := io.ReadFull(rand.Reader, p); err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(p), nil +} + +// Octet types from RFC 2616. +var octetTypes [256]byte + +const ( + isTokenOctet = 1 << iota + isSpaceOctet +) + +func init() { + // From RFC 2616 + // + // OCTET = + // CHAR = + // CTL = + // CR = + // LF = + // SP = + // HT = + // <"> = + // CRLF = CR LF + // LWS = [CRLF] 1*( SP | HT ) + // TEXT = + // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> + // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT + // token = 1* + // qdtext = > + + for c := 0; c < 256; c++ { + var t byte + isCtl := c <= 31 || c == 127 + isChar := 0 <= c && c <= 127 + isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 + if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { + t |= isSpaceOctet + } + if isChar && !isCtl && !isSeparator { + t |= isTokenOctet + } + octetTypes[c] = t + } +} + +func skipSpace(s string) (rest string) { + i := 0 + for ; i < len(s); i++ { + if octetTypes[s[i]]&isSpaceOctet == 0 { + break + } + } + return s[i:] +} + +func nextToken(s string) (token, rest string) { + i := 0 + for ; i < len(s); i++ { + if octetTypes[s[i]]&isTokenOctet == 0 { + break + } + } + return s[:i], s[i:] +} + +func nextTokenOrQuoted(s string) (value string, rest string) { + if !strings.HasPrefix(s, "\"") { + return nextToken(s) + } + s = s[1:] + for i := 0; i < len(s); i++ { + switch s[i] { + case '"': + return s[:i], s[i+1:] + case '\\': + p := make([]byte, len(s)-1) + j := copy(p, s[:i]) + escape := true + for i = i + 1; i < len(s); i++ { + b := s[i] + switch { + case escape: + escape = false + p[j] = b + j++ + case b == '\\': + escape = true + case b == '"': + return string(p[:j]), s[i+1:] + default: + p[j] = b + j++ + } + } + return "", "" + } + } + return "", "" +} + +// equalASCIIFold returns true if s is equal to t with ASCII case folding. +func equalASCIIFold(s, t string) bool { + for s != "" && t != "" { + sr, size := utf8.DecodeRuneInString(s) + s = s[size:] + tr, size := utf8.DecodeRuneInString(t) + t = t[size:] + if sr == tr { + continue + } + if 'A' <= sr && sr <= 'Z' { + sr = sr + 'a' - 'A' + } + if 'A' <= tr && tr <= 'Z' { + tr = tr + 'a' - 'A' + } + if sr != tr { + return false + } + } + return s == t +} + +// tokenListContainsValue returns true if the 1#token header with the given +// name contains a token equal to value with ASCII case folding. +func tokenListContainsValue(header http.Header, name string, value string) bool { +headers: + for _, s := range header[name] { + for { + var t string + t, s = nextToken(skipSpace(s)) + if t == "" { + continue headers + } + s = skipSpace(s) + if s != "" && s[0] != ',' { + continue headers + } + if equalASCIIFold(t, value) { + return true + } + if s == "" { + continue headers + } + s = s[1:] + } + } + return false +} + +// parseExtensions parses WebSocket extensions from a header. +func parseExtensions(header http.Header) []map[string]string { + // From RFC 6455: + // + // Sec-WebSocket-Extensions = extension-list + // extension-list = 1#extension + // extension = extension-token *( ";" extension-param ) + // extension-token = registered-token + // registered-token = token + // extension-param = token [ "=" (token | quoted-string) ] + // ;When using the quoted-string syntax variant, the value + // ;after quoted-string unescaping MUST conform to the + // ;'token' ABNF. + + var result []map[string]string +headers: + for _, s := range header["Sec-Websocket-Extensions"] { + for { + var t string + t, s = nextToken(skipSpace(s)) + if t == "" { + continue headers + } + ext := map[string]string{"": t} + for { + s = skipSpace(s) + if !strings.HasPrefix(s, ";") { + break + } + var k string + k, s = nextToken(skipSpace(s[1:])) + if k == "" { + continue headers + } + s = skipSpace(s) + var v string + if strings.HasPrefix(s, "=") { + v, s = nextTokenOrQuoted(skipSpace(s[1:])) + s = skipSpace(s) + } + if s != "" && s[0] != ',' && s[0] != ';' { + continue headers + } + ext[k] = v + } + if s != "" && s[0] != ',' { + continue headers + } + result = append(result, ext) + if s == "" { + continue headers + } + s = s[1:] + } + } + return result +} diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go new file mode 100644 index 0000000..2e668f6 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/x_net_proxy.go @@ -0,0 +1,473 @@ +// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. +//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy + +// Package proxy provides support for a variety of protocols to proxy network +// data. +// + +package websocket + +import ( + "errors" + "io" + "net" + "net/url" + "os" + "strconv" + "strings" + "sync" +) + +type proxy_direct struct{} + +// Direct is a direct proxy: one that makes network connections directly. +var proxy_Direct = proxy_direct{} + +func (proxy_direct) Dial(network, addr string) (net.Conn, error) { + return net.Dial(network, addr) +} + +// A PerHost directs connections to a default Dialer unless the host name +// requested matches one of a number of exceptions. +type proxy_PerHost struct { + def, bypass proxy_Dialer + + bypassNetworks []*net.IPNet + bypassIPs []net.IP + bypassZones []string + bypassHosts []string +} + +// NewPerHost returns a PerHost Dialer that directs connections to either +// defaultDialer or bypass, depending on whether the connection matches one of +// the configured rules. +func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost { + return &proxy_PerHost{ + def: defaultDialer, + bypass: bypass, + } +} + +// Dial connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + return p.dialerForRequest(host).Dial(network, addr) +} + +func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer { + if ip := net.ParseIP(host); ip != nil { + for _, net := range p.bypassNetworks { + if net.Contains(ip) { + return p.bypass + } + } + for _, bypassIP := range p.bypassIPs { + if bypassIP.Equal(ip) { + return p.bypass + } + } + return p.def + } + + for _, zone := range p.bypassZones { + if strings.HasSuffix(host, zone) { + return p.bypass + } + if host == zone[1:] { + // For a zone ".example.com", we match "example.com" + // too. + return p.bypass + } + } + for _, bypassHost := range p.bypassHosts { + if bypassHost == host { + return p.bypass + } + } + return p.def +} + +// AddFromString parses a string that contains comma-separated values +// specifying hosts that should use the bypass proxy. Each value is either an +// IP address, a CIDR range, a zone (*.example.com) or a host name +// (localhost). A best effort is made to parse the string and errors are +// ignored. +func (p *proxy_PerHost) AddFromString(s string) { + hosts := strings.Split(s, ",") + for _, host := range hosts { + host = strings.TrimSpace(host) + if len(host) == 0 { + continue + } + if strings.Contains(host, "/") { + // We assume that it's a CIDR address like 127.0.0.0/8 + if _, net, err := net.ParseCIDR(host); err == nil { + p.AddNetwork(net) + } + continue + } + if ip := net.ParseIP(host); ip != nil { + p.AddIP(ip) + continue + } + if strings.HasPrefix(host, "*.") { + p.AddZone(host[1:]) + continue + } + p.AddHost(host) + } +} + +// AddIP specifies an IP address that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match an IP. +func (p *proxy_PerHost) AddIP(ip net.IP) { + p.bypassIPs = append(p.bypassIPs, ip) +} + +// AddNetwork specifies an IP range that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match. +func (p *proxy_PerHost) AddNetwork(net *net.IPNet) { + p.bypassNetworks = append(p.bypassNetworks, net) +} + +// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of +// "example.com" matches "example.com" and all of its subdomains. +func (p *proxy_PerHost) AddZone(zone string) { + if strings.HasSuffix(zone, ".") { + zone = zone[:len(zone)-1] + } + if !strings.HasPrefix(zone, ".") { + zone = "." + zone + } + p.bypassZones = append(p.bypassZones, zone) +} + +// AddHost specifies a host name that will use the bypass proxy. +func (p *proxy_PerHost) AddHost(host string) { + if strings.HasSuffix(host, ".") { + host = host[:len(host)-1] + } + p.bypassHosts = append(p.bypassHosts, host) +} + +// A Dialer is a means to establish a connection. +type proxy_Dialer interface { + // Dial connects to the given address via the proxy. + Dial(network, addr string) (c net.Conn, err error) +} + +// Auth contains authentication parameters that specific Dialers may require. +type proxy_Auth struct { + User, Password string +} + +// FromEnvironment returns the dialer specified by the proxy related variables in +// the environment. +func proxy_FromEnvironment() proxy_Dialer { + allProxy := proxy_allProxyEnv.Get() + if len(allProxy) == 0 { + return proxy_Direct + } + + proxyURL, err := url.Parse(allProxy) + if err != nil { + return proxy_Direct + } + proxy, err := proxy_FromURL(proxyURL, proxy_Direct) + if err != nil { + return proxy_Direct + } + + noProxy := proxy_noProxyEnv.Get() + if len(noProxy) == 0 { + return proxy + } + + perHost := proxy_NewPerHost(proxy, proxy_Direct) + perHost.AddFromString(noProxy) + return perHost +} + +// proxySchemes is a map from URL schemes to a function that creates a Dialer +// from a URL with such a scheme. +var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error) + +// RegisterDialerType takes a URL scheme and a function to generate Dialers from +// a URL with that scheme and a forwarding Dialer. Registered schemes are used +// by FromURL. +func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) { + if proxy_proxySchemes == nil { + proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) + } + proxy_proxySchemes[scheme] = f +} + +// FromURL returns a Dialer given a URL specification and an underlying +// Dialer for it to make network requests. +func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) { + var auth *proxy_Auth + if u.User != nil { + auth = new(proxy_Auth) + auth.User = u.User.Username() + if p, ok := u.User.Password(); ok { + auth.Password = p + } + } + + switch u.Scheme { + case "socks5": + return proxy_SOCKS5("tcp", u.Host, auth, forward) + } + + // If the scheme doesn't match any of the built-in schemes, see if it + // was registered by another package. + if proxy_proxySchemes != nil { + if f, ok := proxy_proxySchemes[u.Scheme]; ok { + return f(u, forward) + } + } + + return nil, errors.New("proxy: unknown scheme: " + u.Scheme) +} + +var ( + proxy_allProxyEnv = &proxy_envOnce{ + names: []string{"ALL_PROXY", "all_proxy"}, + } + proxy_noProxyEnv = &proxy_envOnce{ + names: []string{"NO_PROXY", "no_proxy"}, + } +) + +// envOnce looks up an environment variable (optionally by multiple +// names) once. It mitigates expensive lookups on some platforms +// (e.g. Windows). +// (Borrowed from net/http/transport.go) +type proxy_envOnce struct { + names []string + once sync.Once + val string +} + +func (e *proxy_envOnce) Get() string { + e.once.Do(e.init) + return e.val +} + +func (e *proxy_envOnce) init() { + for _, n := range e.names { + e.val = os.Getenv(n) + if e.val != "" { + return + } + } +} + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address +// with an optional username and password. See RFC 1928 and RFC 1929. +func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) { + s := &proxy_socks5{ + network: network, + addr: addr, + forward: forward, + } + if auth != nil { + s.user = auth.User + s.password = auth.Password + } + + return s, nil +} + +type proxy_socks5 struct { + user, password string + network, addr string + forward proxy_Dialer +} + +const proxy_socks5Version = 5 + +const ( + proxy_socks5AuthNone = 0 + proxy_socks5AuthPassword = 2 +) + +const proxy_socks5Connect = 1 + +const ( + proxy_socks5IP4 = 1 + proxy_socks5Domain = 3 + proxy_socks5IP6 = 4 +) + +var proxy_socks5Errors = []string{ + "", + "general failure", + "connection forbidden", + "network unreachable", + "host unreachable", + "connection refused", + "TTL expired", + "command not supported", + "address type not supported", +} + +// Dial connects to the address addr on the given network via the SOCKS5 proxy. +func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) { + switch network { + case "tcp", "tcp6", "tcp4": + default: + return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) + } + + conn, err := s.forward.Dial(s.network, s.addr) + if err != nil { + return nil, err + } + if err := s.connect(conn, addr); err != nil { + conn.Close() + return nil, err + } + return conn, nil +} + +// connect takes an existing connection to a socks5 proxy server, +// and commands the server to extend that connection to target, +// which must be a canonical address with a host and port. +func (s *proxy_socks5) connect(conn net.Conn, target string) error { + host, portStr, err := net.SplitHostPort(target) + if err != nil { + return err + } + + port, err := strconv.Atoi(portStr) + if err != nil { + return errors.New("proxy: failed to parse port number: " + portStr) + } + if port < 1 || port > 0xffff { + return errors.New("proxy: port number out of range: " + portStr) + } + + // the size here is just an estimate + buf := make([]byte, 0, 6+len(host)) + + buf = append(buf, proxy_socks5Version) + if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { + buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword) + } else { + buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone) + } + + if _, err := conn.Write(buf); err != nil { + return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + if _, err := io.ReadFull(conn, buf[:2]); err != nil { + return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + if buf[0] != 5 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) + } + if buf[1] == 0xff { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") + } + + // See RFC 1929 + if buf[1] == proxy_socks5AuthPassword { + buf = buf[:0] + buf = append(buf, 1 /* password protocol version */) + buf = append(buf, uint8(len(s.user))) + buf = append(buf, s.user...) + buf = append(buf, uint8(len(s.password))) + buf = append(buf, s.password...) + + if _, err := conn.Write(buf); err != nil { + return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + if _, err := io.ReadFull(conn, buf[:2]); err != nil { + return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + if buf[1] != 0 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") + } + } + + buf = buf[:0] + buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */) + + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + buf = append(buf, proxy_socks5IP4) + ip = ip4 + } else { + buf = append(buf, proxy_socks5IP6) + } + buf = append(buf, ip...) + } else { + if len(host) > 255 { + return errors.New("proxy: destination host name too long: " + host) + } + buf = append(buf, proxy_socks5Domain) + buf = append(buf, byte(len(host))) + buf = append(buf, host...) + } + buf = append(buf, byte(port>>8), byte(port)) + + if _, err := conn.Write(buf); err != nil { + return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + if _, err := io.ReadFull(conn, buf[:4]); err != nil { + return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + failure := "unknown error" + if int(buf[1]) < len(proxy_socks5Errors) { + failure = proxy_socks5Errors[buf[1]] + } + + if len(failure) > 0 { + return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) + } + + bytesToDiscard := 0 + switch buf[3] { + case proxy_socks5IP4: + bytesToDiscard = net.IPv4len + case proxy_socks5IP6: + bytesToDiscard = net.IPv6len + case proxy_socks5Domain: + _, err := io.ReadFull(conn, buf[:1]) + if err != nil { + return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + bytesToDiscard = int(buf[0]) + default: + return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) + } + + if cap(buf) < bytesToDiscard { + buf = make([]byte, bytesToDiscard) + } else { + buf = buf[:bytesToDiscard] + } + if _, err := io.ReadFull(conn, buf); err != nil { + return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + // Also need to discard the port number + if _, err := io.ReadFull(conn, buf[:2]); err != nil { + return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) + } + + return nil +} diff --git a/vendor/github.com/gxed/hashland/LICENSE b/vendor/github.com/gxed/hashland/keccakpg/LICENSE similarity index 100% rename from vendor/github.com/gxed/hashland/LICENSE rename to vendor/github.com/gxed/hashland/keccakpg/LICENSE diff --git a/vendor/github.com/gxed/hashland/keccakpg/go.mod b/vendor/github.com/gxed/hashland/keccakpg/go.mod new file mode 100644 index 0000000..da524d9 --- /dev/null +++ b/vendor/github.com/gxed/hashland/keccakpg/go.mod @@ -0,0 +1 @@ +module github.com/gxed/hashland/keccakpg diff --git a/vendor/github.com/spaolacci/murmur3/LICENSE b/vendor/github.com/gxed/hashland/murmur3/LICENSE similarity index 100% rename from vendor/github.com/spaolacci/murmur3/LICENSE rename to vendor/github.com/gxed/hashland/murmur3/LICENSE diff --git a/vendor/github.com/spaolacci/murmur3/README.md b/vendor/github.com/gxed/hashland/murmur3/README.md similarity index 97% rename from vendor/github.com/spaolacci/murmur3/README.md rename to vendor/github.com/gxed/hashland/murmur3/README.md index e463678..1edf623 100644 --- a/vendor/github.com/spaolacci/murmur3/README.md +++ b/vendor/github.com/gxed/hashland/murmur3/README.md @@ -1,8 +1,6 @@ murmur3 ======= -[![Build Status](https://travis-ci.org/spaolacci/murmur3.svg?branch=master)](https://travis-ci.org/spaolacci/murmur3) - Native Go implementation of Austin Appleby's third MurmurHash revision (aka MurmurHash3). diff --git a/vendor/github.com/gxed/hashland/murmur3/go.mod b/vendor/github.com/gxed/hashland/murmur3/go.mod new file mode 100644 index 0000000..bef2395 --- /dev/null +++ b/vendor/github.com/gxed/hashland/murmur3/go.mod @@ -0,0 +1 @@ +module github.com/gxed/hashland/murmur3 diff --git a/vendor/github.com/spaolacci/murmur3/murmur.go b/vendor/github.com/gxed/hashland/murmur3/murmur.go similarity index 95% rename from vendor/github.com/spaolacci/murmur3/murmur.go rename to vendor/github.com/gxed/hashland/murmur3/murmur.go index 1252cf7..f99557c 100644 --- a/vendor/github.com/spaolacci/murmur3/murmur.go +++ b/vendor/github.com/gxed/hashland/murmur3/murmur.go @@ -3,6 +3,8 @@ // license that can be found in the LICENSE file. /* +Native (and fast) implementation of Austin Appleby's MurmurHash3. + Package murmur3 implements Austin Appleby's non-cryptographic MurmurHash3. Reference implementation: @@ -24,7 +26,6 @@ type digest struct { clen int // Digested input cumulative length. tail []byte // 0 to Size()-1 bytes view of `buf'. buf [16]byte // Expected (but not required) to be Size() large. - seed uint32 // Seed for initializing the hash. bmixer } diff --git a/vendor/github.com/spaolacci/murmur3/murmur128.go b/vendor/github.com/gxed/hashland/murmur3/murmur128.go similarity index 80% rename from vendor/github.com/spaolacci/murmur3/murmur128.go rename to vendor/github.com/gxed/hashland/murmur3/murmur128.go index a4b618b..16c34d6 100644 --- a/vendor/github.com/spaolacci/murmur3/murmur128.go +++ b/vendor/github.com/gxed/hashland/murmur3/murmur128.go @@ -18,7 +18,6 @@ var ( _ bmixer = new(digest128) ) -// Hash128 represents a 128-bit hasher // Hack: the standard api doesn't define any Hash128 interface. type Hash128 interface { hash.Hash @@ -32,13 +31,8 @@ type digest128 struct { h2 uint64 // Unfinalized running hash part 2. } -// New128 returns a 128-bit hasher -func New128() Hash128 { return New128WithSeed(0) } - -// New128WithSeed returns a 128-bit hasher set with explicit seed value -func New128WithSeed(seed uint32) Hash128 { +func New128() Hash128 { d := new(digest128) - d.seed = seed d.bmixer = d d.Reset() return d @@ -46,10 +40,10 @@ func New128WithSeed(seed uint32) Hash128 { func (d *digest128) Size() int { return 16 } -func (d *digest128) reset() { d.h1, d.h2 = uint64(d.seed), uint64(d.seed) } +func (d *digest128) reset() { d.h1, d.h2 = 0, 0 } func (d *digest128) Sum(b []byte) []byte { - h1, h2 := d.Sum128() + h1, h2 := d.h1, d.h2 return append(b, byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1), @@ -187,16 +181,8 @@ func rotl64(x uint64, r byte) uint64 { // hasher := New128() // hasher.Write(data) // return hasher.Sum128() -func Sum128(data []byte) (h1 uint64, h2 uint64) { return Sum128WithSeed(data, 0) } - -// Sum128WithSeed returns the MurmurHash3 sum of data. It is equivalent to the -// following sequence (without the extra burden and the extra allocation): -// hasher := New128WithSeed(seed) -// hasher.Write(data) -// return hasher.Sum128() -func Sum128WithSeed(data []byte, seed uint32) (h1 uint64, h2 uint64) { - d := &digest128{h1: uint64(seed), h2: uint64(seed)} - d.seed = seed +func Sum128(data []byte) (h1 uint64, h2 uint64) { + d := &digest128{h1: 0, h2: 0} d.tail = d.bmix(data) d.clen = len(data) return d.Sum128() diff --git a/vendor/github.com/spaolacci/murmur3/murmur32.go b/vendor/github.com/gxed/hashland/murmur3/murmur32.go similarity index 77% rename from vendor/github.com/spaolacci/murmur3/murmur32.go rename to vendor/github.com/gxed/hashland/murmur3/murmur32.go index e32c995..bc89d26 100644 --- a/vendor/github.com/spaolacci/murmur3/murmur32.go +++ b/vendor/github.com/gxed/hashland/murmur3/murmur32.go @@ -11,7 +11,6 @@ import ( var ( _ hash.Hash = new(digest32) _ hash.Hash32 = new(digest32) - _ bmixer = new(digest32) ) const ( @@ -25,13 +24,8 @@ type digest32 struct { h1 uint32 // Unfinalized running hash. } -// New32 returns new 32-bit hasher -func New32() hash.Hash32 { return New32WithSeed(0) } - -// New32WithSeed returns new 32-bit hasher set with explicit seed value -func New32WithSeed(seed uint32) hash.Hash32 { +func New32() hash.Hash32 { d := new(digest32) - d.seed = seed d.bmixer = d d.Reset() return d @@ -39,10 +33,10 @@ func New32WithSeed(seed uint32) hash.Hash32 { func (d *digest32) Size() int { return 4 } -func (d *digest32) reset() { d.h1 = d.seed } +func (d *digest32) reset() { d.h1 = 0 } func (d *digest32) Sum(b []byte) []byte { - h := d.Sum32() + h := d.h1 return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) } @@ -60,7 +54,7 @@ func (d *digest32) bmix(p []byte) (tail []byte) { h1 ^= k1 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) - h1 = h1*4 + h1 + 0xe6546b64 + h1 = h1*5 + 0xe6546b64 } d.h1 = h1 return p[nblocks*d.Size():] @@ -108,16 +102,9 @@ func rotl32(x uint32, r byte) uint32 { // hasher := New32() // hasher.Write(data) // return hasher.Sum32() -func Sum32(data []byte) uint32 { return Sum32WithSeed(data, 0) } - -// Sum32WithSeed returns the MurmurHash3 sum of data. It is equivalent to the -// following sequence (without the extra burden and the extra allocation): -// hasher := New32WithSeed(seed) -// hasher.Write(data) -// return hasher.Sum32() -func Sum32WithSeed(data []byte, seed uint32) uint32 { +func Sum32(data []byte) uint32 { - h1 := seed + var h1 uint32 = 0 nblocks := len(data) / 4 var p uintptr @@ -134,7 +121,7 @@ func Sum32WithSeed(data []byte, seed uint32) uint32 { h1 ^= k1 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) - h1 = h1*4 + h1 + 0xe6546b64 + h1 = h1*5 + 0xe6546b64 } tail := data[nblocks*4:] diff --git a/vendor/github.com/spaolacci/murmur3/murmur64.go b/vendor/github.com/gxed/hashland/murmur3/murmur64.go similarity index 53% rename from vendor/github.com/spaolacci/murmur3/murmur64.go rename to vendor/github.com/gxed/hashland/murmur3/murmur64.go index 65a410a..fdd4398 100644 --- a/vendor/github.com/spaolacci/murmur3/murmur64.go +++ b/vendor/github.com/gxed/hashland/murmur3/murmur64.go @@ -14,17 +14,13 @@ var ( // digest64 is half a digest128. type digest64 digest128 -// New64 returns a 64-bit hasher -func New64() hash.Hash64 { return New64WithSeed(0) } - -// New64WithSeed returns a 64-bit hasher set with explicit seed value -func New64WithSeed(seed uint32) hash.Hash64 { - d := (*digest64)(New128WithSeed(seed).(*digest128)) +func New64() hash.Hash64 { + d := (*digest64)(New128().(*digest128)) return d } func (d *digest64) Sum(b []byte) []byte { - h1 := d.Sum64() + h1 := d.h1 return append(b, byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1)) @@ -40,16 +36,8 @@ func (d *digest64) Sum64() uint64 { // hasher := New64() // hasher.Write(data) // return hasher.Sum64() -func Sum64(data []byte) uint64 { return Sum64WithSeed(data, 0) } - -// Sum64WithSeed returns the MurmurHash3 sum of data. It is equivalent to the -// following sequence (without the extra burden and the extra allocation): -// hasher := New64WithSeed(seed) -// hasher.Write(data) -// return hasher.Sum64() -func Sum64WithSeed(data []byte, seed uint32) uint64 { - d := &digest128{h1: uint64(seed), h2: uint64(seed)} - d.seed = seed +func Sum64(data []byte) uint64 { + d := &digest128{h1: 0, h2: 0} d.tail = d.bmix(data) d.clen = len(data) h1, _ := d.Sum128() diff --git a/vendor/github.com/huin/goupnp/.gitignore b/vendor/github.com/huin/goupnp/.gitignore index 09ef375..7a6e0eb 100644 --- a/vendor/github.com/huin/goupnp/.gitignore +++ b/vendor/github.com/huin/goupnp/.gitignore @@ -1 +1,2 @@ -/gotasks/specs +*.zip +*.sublime-workspace \ No newline at end of file diff --git a/vendor/github.com/huin/goupnp/README.md b/vendor/github.com/huin/goupnp/README.md index 433ba5c..7c63903 100644 --- a/vendor/github.com/huin/goupnp/README.md +++ b/vendor/github.com/huin/goupnp/README.md @@ -25,15 +25,19 @@ Core components: Regenerating dcps generated source code: ---------------------------------------- -1. Install gotasks: `go get -u github.com/jingweno/gotask` -2. Change to the gotasks directory: `cd gotasks` -3. Run specgen task: `gotask specgen` +1. Build code generator: + + `go get -u github.com/huin/goupnp/cmd/goupnpdcpgen` + +2. Regenerate the code: + + `go generate ./...` Supporting additional UPnP devices and services: ------------------------------------------------ Supporting additional services is, in the trivial case, simply a matter of -adding the service to the `dcpMetadata` whitelist in `gotasks/specgen_task.go`, +adding the service to the `dcpMetadata` whitelist in `cmd/goupnpdcpgen/metadata.go`, regenerating the source code (see above), and committing that source code. However, it would be helpful if anyone needing such a service could test the diff --git a/vendor/github.com/huin/goupnp/dcps/internetgateway1/gen.go b/vendor/github.com/huin/goupnp/dcps/internetgateway1/gen.go new file mode 100644 index 0000000..2b146a3 --- /dev/null +++ b/vendor/github.com/huin/goupnp/dcps/internetgateway1/gen.go @@ -0,0 +1,2 @@ +//go:generate goupnpdcpgen -dcp_name internetgateway1 +package internetgateway1 diff --git a/vendor/github.com/huin/goupnp/dcps/internetgateway2/gen.go b/vendor/github.com/huin/goupnp/dcps/internetgateway2/gen.go new file mode 100644 index 0000000..752058b --- /dev/null +++ b/vendor/github.com/huin/goupnp/dcps/internetgateway2/gen.go @@ -0,0 +1,2 @@ +//go:generate goupnpdcpgen -dcp_name internetgateway2 +package internetgateway2 diff --git a/vendor/github.com/huin/goupnp/go.mod b/vendor/github.com/huin/goupnp/go.mod new file mode 100644 index 0000000..e4a078f --- /dev/null +++ b/vendor/github.com/huin/goupnp/go.mod @@ -0,0 +1,7 @@ +module github.com/huin/goupnp + +require ( + github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 + golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 + golang.org/x/text v0.3.0 // indirect +) diff --git a/vendor/github.com/huin/goupnp/go.sum b/vendor/github.com/huin/goupnp/go.sum new file mode 100644 index 0000000..3e75869 --- /dev/null +++ b/vendor/github.com/huin/goupnp/go.sum @@ -0,0 +1,6 @@ +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/huin/goupnp/goupnp.sublime-project b/vendor/github.com/huin/goupnp/goupnp.sublime-project new file mode 100644 index 0000000..24db303 --- /dev/null +++ b/vendor/github.com/huin/goupnp/goupnp.sublime-project @@ -0,0 +1,8 @@ +{ + "folders": + [ + { + "path": "." + } + ] +} diff --git a/vendor/github.com/jackpal/gateway/gateway_common.go b/vendor/github.com/jackpal/gateway/gateway_common.go index 74cc7b2..441ea62 100644 --- a/vendor/github.com/jackpal/gateway/gateway_common.go +++ b/vendor/github.com/jackpal/gateway/gateway_common.go @@ -39,7 +39,7 @@ func parseWindowsRoutePrint(output []byte) (net.IP, error) { return nil, errNoGateway } -func parseLinuxIPRoute(output []byte) (net.IP, error) { +func parseLinuxIPRouteShow(output []byte) (net.IP, error) { // Linux '/usr/bin/ip route show' format looks like this: // default via 192.168.178.1 dev wlp3s0 metric 303 // 192.168.178.0/24 dev wlp3s0 proto kernel scope link src 192.168.178.76 metric 303 @@ -57,6 +57,23 @@ func parseLinuxIPRoute(output []byte) (net.IP, error) { return nil, errNoGateway } +func parseLinuxIPRouteGet(output []byte) (net.IP, error) { + // Linux '/usr/bin/ip route get 8.8.8.8' format looks like this: + // 8.8.8.8 via 10.0.1.1 dev eth0 src 10.0.1.36 uid 2000 + lines := strings.Split(string(output), "\n") + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) >= 2 && fields[1] == "via" { + ip := net.ParseIP(fields[2]) + if ip != nil { + return ip, nil + } + } + } + + return nil, errNoGateway +} + func parseLinuxRoute(output []byte) (net.IP, error) { // Linux route out format is always like this: // Kernel IP routing table diff --git a/vendor/github.com/jackpal/gateway/gateway_linux.go b/vendor/github.com/jackpal/gateway/gateway_linux.go index c705632..aacaa88 100644 --- a/vendor/github.com/jackpal/gateway/gateway_linux.go +++ b/vendor/github.com/jackpal/gateway/gateway_linux.go @@ -8,23 +8,36 @@ import ( func DiscoverGateway() (ip net.IP, err error) { ip, err = discoverGatewayUsingRoute() if err != nil { - ip, err = discoverGatewayUsingIp() + ip, err = discoverGatewayUsingIpRouteShow() + } + if err != nil { + ip, err = discoverGatewayUsingIpRouteGet() } return } -func discoverGatewayUsingIp() (net.IP, error) { - routeCmd := exec.Command("/usr/bin/ip", "route", "show") +func discoverGatewayUsingIpRouteShow() (net.IP, error) { + routeCmd := exec.Command("ip", "route", "show") + output, err := routeCmd.CombinedOutput() + if err != nil { + return nil, err + } + + return parseLinuxIPRouteShow(output) +} + +func discoverGatewayUsingIpRouteGet() (net.IP, error) { + routeCmd := exec.Command("ip", "route", "get", "8.8.8.8") output, err := routeCmd.CombinedOutput() if err != nil { return nil, err } - return parseLinuxIPRoute(output) + return parseLinuxIPRouteGet(output) } func discoverGatewayUsingRoute() (net.IP, error) { - routeCmd := exec.Command("/usr/bin/route", "-n") + routeCmd := exec.Command("route", "-n") output, err := routeCmd.CombinedOutput() if err != nil { return nil, err diff --git a/vendor/github.com/jackpal/gateway/gateway_windows.go b/vendor/github.com/jackpal/gateway/gateway_windows.go index 4e944ee..2419c83 100644 --- a/vendor/github.com/jackpal/gateway/gateway_windows.go +++ b/vendor/github.com/jackpal/gateway/gateway_windows.go @@ -3,10 +3,12 @@ package gateway import ( "net" "os/exec" + "syscall" ) func DiscoverGateway() (ip net.IP, err error) { routeCmd := exec.Command("route", "print", "0.0.0.0") + routeCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} output, err := routeCmd.CombinedOutput() if err != nil { return nil, err diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/.travis.yml b/vendor/github.com/libp2p/go-libp2p-gorpc/.travis.yml index 92ca7bb..9e8b960 100644 --- a/vendor/github.com/libp2p/go-libp2p-gorpc/.travis.yml +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/.travis.yml @@ -2,8 +2,6 @@ language: go go: - 1.11.x install: -- go get golang.org/x/tools/cmd/cover -- go get github.com/mattn/goveralls - make deps script: - make test diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/client.go b/vendor/github.com/libp2p/go-libp2p-gorpc/client.go index 7f965a1..10581e3 100644 --- a/vendor/github.com/libp2p/go-libp2p-gorpc/client.go +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/client.go @@ -5,18 +5,31 @@ import ( "io" "sync" + stats "github.com/libp2p/go-libp2p-gorpc/stats" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" protocol "github.com/libp2p/go-libp2p-protocol" ) +// ClientOption allows for functional setting of options on a Client. +type ClientOption func(*Client) + +// WithClientStatsHandler providers a implementation of stats.Handler to be +// used by the Client. +func WithClientStatsHandler(h stats.Handler) ClientOption { + return func(c *Client) { + c.statsHandler = h + } +} + // Client represents an RPC client which can perform calls to a remote // (or local, see below) Server. type Client struct { - host host.Host - protocol protocol.ID - server *Server + host host.Host + protocol protocol.ID + server *Server + statsHandler stats.Handler } // NewClient returns a new Client which uses the given LibP2P host @@ -27,18 +40,24 @@ type Client struct { // The client returned will not be able to run any local requests // if the Server is sharing the same LibP2P host. See NewClientWithServer // if this is a usecase. -func NewClient(h host.Host, p protocol.ID) *Client { - return &Client{ +func NewClient(h host.Host, p protocol.ID, opts ...ClientOption) *Client { + c := &Client{ host: h, protocol: p, } + + for _, opt := range opts { + opt(c) + } + + return c } // NewClientWithServer takes an additional RPC Server and returns a Client // which will perform any requests to itself by using the given Server.Call() // directly. It is assumed that Client and Server share the same LibP2P host. -func NewClientWithServer(h host.Host, p protocol.ID, s *Server) *Client { - c := NewClient(h, p) +func NewClientWithServer(h host.Host, p protocol.ID, s *Server, opts ...ClientOption) *Client { + c := NewClient(h, p, opts...) c.server = s return c } diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/package.json b/vendor/github.com/libp2p/go-libp2p-gorpc/package.json index 31bab35..efe9bc2 100644 --- a/vendor/github.com/libp2p/go-libp2p-gorpc/package.json +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/package.json @@ -9,15 +9,15 @@ "gxDependencies": [ { "author": "whyrusleeping", - "hash": "QmUDTcnDp2WssbmiDLC6aYurUeyt7QeRakHUQMxA2mZ5iB", + "hash": "QmcNGX5RaxPPCYwa6yGXM1EcUbrreTTinixLcYGmMwf1sx", "name": "go-libp2p", - "version": "6.0.23" + "version": "6.0.35" }, { - "author": "multiformats", - "hash": "QmYMiyZRYDmhMr2phMc4FGrYbsyzvR751BgeobnWroiq2z", - "name": "go-multicodec", - "version": "0.1.7" + "author": "ugorji", + "hash": "QmVTAmbCaPqdfbmpWDCJMQNFxbyJoG2USFsumXmTWY5LFp", + "name": "go-codec", + "version": "2017.10.18" } ], "gxVersion": "0.10.0", @@ -25,6 +25,6 @@ "license": "MIT/BSD", "name": "go-libp2p-gorpc", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "1.0.24" + "version": "1.1.2" } diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/server.go b/vendor/github.com/libp2p/go-libp2p-gorpc/server.go index cf1e2f8..93ca333 100644 --- a/vendor/github.com/libp2p/go-libp2p-gorpc/server.go +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/server.go @@ -50,13 +50,16 @@ import ( "context" "errors" "fmt" + "io" "log" "reflect" "sync" + "time" "unicode" "unicode/utf8" logging "github.com/ipfs/go-log" + stats "github.com/libp2p/go-libp2p-gorpc/stats" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" @@ -99,6 +102,17 @@ type Response struct { ErrType responseErr } +// ServerOption allows for functional setting of options on a Server. +type ServerOption func(*Server) + +// WithServerStatsHandler providers a implementation of stats.Handler to be +// used by the Server. +func WithServerStatsHandler(h stats.Handler) ServerOption { + return func(s *Server) { + s.statsHandler = h + } +} + // Server is an LibP2P RPC server. It can register services which comply to the // limitations outlined in the package description and it will call the relevant // methods when receiving requests from a Client. @@ -107,8 +121,9 @@ type Response struct { // by the client. The LibP2P host must be already correctly configured to // be able to handle connections from clients. type Server struct { - host host.Host - protocol protocol.ID + host host.Host + protocol protocol.ID + statsHandler stats.Handler mu sync.RWMutex // protects the serviceMap serviceMap map[string]*service @@ -116,12 +131,16 @@ type Server struct { // NewServer creates a Server object with the given LibP2P host // and protocol. -func NewServer(h host.Host, p protocol.ID) *Server { +func NewServer(h host.Host, p protocol.ID, opts ...ServerOption) *Server { s := &Server{ host: h, protocol: p, } + for _, opt := range opts { + opt(s) + } + if h != nil { h.SetStreamHandler(p, func(stream inet.Stream) { sWrap := wrapStream(stream) @@ -147,14 +166,37 @@ func (server *Server) ID() peer.ID { func (server *Server) handle(s *streamWrap) error { logger.Debugf("%s: handling remote RPC", server.host.ID().Pretty()) + var err error var svcID ServiceID var argv, replyv reflect.Value + ctx := context.Background() - err := s.dec.Decode(&svcID) + err = s.dec.Decode(&svcID) if err != nil { return newServerError(err) } + sh := server.statsHandler + if sh != nil { + ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: "/" + svcID.Name + "/" + svcID.Method}) + beginTime := time.Now() + begin := &stats.Begin{ + BeginTime: beginTime, + } + sh.HandleRPC(ctx, begin) + + defer func() { + end := &stats.End{ + BeginTime: beginTime, + EndTime: time.Now(), + } + if err != nil && err != io.EOF { + end.Error = newServerError(err) + } + sh.HandleRPC(ctx, end) + }() + } + logger.Debugf("RPC ServiceID is %s.%s", svcID.Name, svcID.Method) service, mtype, err := server.getService(svcID) @@ -180,11 +222,19 @@ func (server *Server) handle(s *streamWrap) error { replyv = reflect.New(mtype.ReplyType.Elem()) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(ctx) defer cancel() ctxv := reflect.ValueOf(ctx) + // TODO(lanzafame): once I figure out a + // good to get the size of the payload. + // inPayload := &stats.InPayload{ + // Length: , + // RecvTime: beginTime, + // } + // sh.HandleRPC(ctx, inPayload) + // This is a connection watchdog. We do not // need to read from this stream anymore. // However we'd like to know if the other side is closed @@ -245,6 +295,35 @@ func sendResponse(s *streamWrap, resp *Response, body interface{}) error { // create streams between a server and a client which share the same // host. See NewClientWithServer() for more info. func (server *Server) Call(call *Call) error { + var err error + + sh := server.statsHandler + if sh != nil { + call.ctx = sh.TagRPC(call.ctx, &stats.RPCTagInfo{FullMethodName: "/" + call.SvcID.Name + "/" + call.SvcID.Method}) + beginTime := time.Now() + begin := &stats.Begin{ + BeginTime: beginTime, + } + sh.HandleRPC(call.ctx, begin) + + inPayload := &stats.InPayload{ + Payload: call, + Length: int(reflect.TypeOf(call.Args).Size()), + RecvTime: beginTime, + } + sh.HandleRPC(call.ctx, inPayload) + defer func() { + end := &stats.End{ + BeginTime: beginTime, + EndTime: time.Now(), + } + if err != nil && err != io.EOF { + end.Error = newServerError(err) + } + sh.HandleRPC(call.ctx, end) + }() + } + var argv, replyv reflect.Value service, mtype, err := server.getService(call.SvcID) if err != nil { @@ -288,6 +367,7 @@ func (server *Server) Call(call *Call) error { // Call service and respond function := mtype.method.Func + // Invoke the method, providing a new value for the reply. returnValues := function.Call( []reflect.Value{ diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/stats/handlers.go b/vendor/github.com/libp2p/go-libp2p-gorpc/stats/handlers.go new file mode 100644 index 0000000..91e1408 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/stats/handlers.go @@ -0,0 +1,19 @@ +package stats + +import "context" + +// RPCTagInfo defines the relevant information needed by RPC context tagger. +type RPCTagInfo struct { + // FullMethodName is the RPC method in the format of /package.service/method. + FullMethodName string +} + +// Handler defines the interface for the related stats handling (e.g., RPCs, connections). +type Handler interface { + // TagRPC can attach some information to the given context. + // The context used for the rest lifetime of the RPC will be derived from + // the returned context. + TagRPC(context.Context, *RPCTagInfo) context.Context + // HandleRPC processes the RPC stats. + HandleRPC(context.Context, RPCStats) +} diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/stats/stats.go b/vendor/github.com/libp2p/go-libp2p-gorpc/stats/stats.go new file mode 100644 index 0000000..8903ab0 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/stats/stats.go @@ -0,0 +1,85 @@ +package stats + +import "time" + +// RPCStats contains stats information about RPCs. +type RPCStats interface { + isRPCStats() + // IsClient returns true if this RPCStats is from client side. + IsClient() bool +} + +// Begin contains stats when an RPC begins. +// FailFast is only valid if this Begin is from client side. +type Begin struct { + // Client is true if this Begin is from client side. + Client bool + // BeginTime is the time when the RPC begins. + BeginTime time.Time +} + +// IsClient indicates if the stats information is from client side. +func (s *Begin) IsClient() bool { return s.Client } + +func (s *Begin) isRPCStats() {} + +// InPayload contains the information for an incoming payload. +type InPayload struct { + // Client is true if this InPayload is from client side. + Client bool + // Payload is the payload with original type. + Payload interface{} + // Data is the serialized message payload. + Data []byte + // Length is the length of uncompressed data. + Length int + // WireLength is the length of data on wire (compressed, signed, encrypted). + WireLength int + // RecvTime is the time when the payload is received. + RecvTime time.Time +} + +// IsClient indicates if the stats information is from client side. +func (s *InPayload) IsClient() bool { return s.Client } + +func (s *InPayload) isRPCStats() {} + +// OutPayload contains the information for an outgoing payload. +type OutPayload struct { + // Client is true if this OutPayload is from client side. + Client bool + // Payload is the payload with original type. + Payload interface{} + // Data is the serialized message payload. + Data []byte + // Length is the length of uncompressed data. + Length int + // WireLength is the length of data on wire (compressed, signed, encrypted). + WireLength int + // SentTime is the time when the payload is sent. + SentTime time.Time +} + +// IsClient indicates if this stats information is from client side. +func (s *OutPayload) IsClient() bool { return s.Client } + +func (s *OutPayload) isRPCStats() {} + +// End contains stats when an RPC ends. +type End struct { + // Client is true if this End is from client side. + Client bool + // BeginTime is the time when the RPC began. + BeginTime time.Time + // EndTime is the time when the RPC ends. + EndTime time.Time + // Error is the error the RPC ended with. It is an error generated from + // status.Status and can be converted back to status.Status using + // status.FromError if non-nil. + Error error +} + +// IsClient indicates if this is from client side. +func (s *End) IsClient() bool { return s.Client } + +func (s *End) isRPCStats() {} diff --git a/vendor/github.com/libp2p/go-libp2p-gorpc/stream_wrap.go b/vendor/github.com/libp2p/go-libp2p-gorpc/stream_wrap.go index 5d05034..2dcfdd1 100644 --- a/vendor/github.com/libp2p/go-libp2p-gorpc/stream_wrap.go +++ b/vendor/github.com/libp2p/go-libp2p-gorpc/stream_wrap.go @@ -4,8 +4,7 @@ import ( "bufio" inet "github.com/libp2p/go-libp2p-net" - multicodec "github.com/multiformats/go-multicodec" - msgpack "github.com/multiformats/go-multicodec/msgpack" + "github.com/ugorji/go/codec" ) // streamWrap wraps a libp2p stream. We encode/decode whenever we @@ -13,8 +12,8 @@ import ( // and bufios with us type streamWrap struct { stream inet.Stream - enc multicodec.Encoder - dec multicodec.Decoder + enc *codec.Encoder + dec *codec.Decoder w *bufio.Writer r *bufio.Reader } @@ -27,8 +26,9 @@ type streamWrap struct { func wrapStream(s inet.Stream) *streamWrap { reader := bufio.NewReader(s) writer := bufio.NewWriter(s) - dec := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Decoder(reader) - enc := msgpack.Multicodec(msgpack.DefaultMsgpackHandle()).Encoder(writer) + h := &codec.MsgpackHandle{} + dec := codec.NewDecoder(reader, h) + enc := codec.NewEncoder(writer, h) return &streamWrap{ stream: s, r: reader, diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/.travis.yml b/vendor/github.com/libp2p/go-libp2p-kad-dht/.travis.yml index 1985a1d..9720741 100644 --- a/vendor/github.com/libp2p/go-libp2p-kad-dht/.travis.yml +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/.travis.yml @@ -9,7 +9,7 @@ env: - IPFS_REUSEPORT=false go: - - 1.9.x + - 1.11.x install: - make deps diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/dht.go b/vendor/github.com/libp2p/go-libp2p-kad-dht/dht.go index 1b4c68c..d08c376 100644 --- a/vendor/github.com/libp2p/go-libp2p-kad-dht/dht.go +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/dht.go @@ -1,5 +1,3 @@ -// Package dht implements a distributed hash table that satisfies the ipfs routing -// interface. This DHT is modeled after kademlia with S/Kademlia modifications. package dht import ( @@ -330,7 +328,7 @@ func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID { return closer } -// betterPeerToQuery returns nearestPeersToQuery, but iff closer than self. +// betterPeersToQuery returns nearestPeersToQuery, but if and only if closer than self. func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID { closer := dht.nearestPeersToQuery(pmes, count) @@ -370,6 +368,11 @@ func (dht *IpfsDHT) Process() goprocess.Process { return dht.proc } +// RoutingTable return dht's routingTable +func (dht *IpfsDHT) RoutingTable() *kb.RoutingTable { + return dht.routingTable +} + // Close calls Process Close func (dht *IpfsDHT) Close() error { return dht.proc.Close() diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/dht_bootstrap.go b/vendor/github.com/libp2p/go-libp2p-kad-dht/dht_bootstrap.go index cb8d3ed..5bf744d 100644 --- a/vendor/github.com/libp2p/go-libp2p-kad-dht/dht_bootstrap.go +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/dht_bootstrap.go @@ -1,5 +1,3 @@ -// Package dht implements a distributed hash table that satisfies the ipfs routing -// interface. This DHT is modeled after Kademlia with S/Kademlia modifications. package dht import ( @@ -13,8 +11,35 @@ import ( periodicproc "github.com/jbenet/goprocess/periodic" peer "github.com/libp2p/go-libp2p-peer" routing "github.com/libp2p/go-libp2p-routing" + multiaddr "github.com/multiformats/go-multiaddr" ) +var DefaultBootstrapPeers []multiaddr.Multiaddr + +func init() { + for _, s := range []string{ + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + } { + ma, err := multiaddr.NewMultiaddr(s) + if err != nil { + panic(err) + } + DefaultBootstrapPeers = append(DefaultBootstrapPeers, ma) + } +} + // BootstrapConfig specifies parameters used bootstrapping the DHT. // // Note there is a tradeoff between the bootstrap period and the diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/doc.go b/vendor/github.com/libp2p/go-libp2p-kad-dht/doc.go new file mode 100644 index 0000000..acbb181 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/doc.go @@ -0,0 +1,3 @@ +// Package dht implements a distributed hash table that satisfies the ipfs routing +// interface. This DHT is modeled after kademlia with S/Kademlia modifications. +package dht diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/package.json b/vendor/github.com/libp2p/go-libp2p-kad-dht/package.json index dd123b2..b4fa975 100644 --- a/vendor/github.com/libp2p/go-libp2p-kad-dht/package.json +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/package.json @@ -8,21 +8,21 @@ }, "gxDependencies": [ { - "hash": "QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae", + "hash": "QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C", "name": "go-log", - "version": "1.5.7" + "version": "1.5.8" }, { "author": "whyrusleeping", - "hash": "QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n", + "hash": "QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s", "name": "go-libp2p-crypto", - "version": "2.0.1" + "version": "2.0.4" }, { "author": "whyrusleeping", - "hash": "QmTRhk7cgjUf2gfQ3p2M9KPECNZEW9XUrmHcFCgog4cPgB", + "hash": "QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY", "name": "go-libp2p-peer", - "version": "2.4.0" + "version": "3.0.0" }, { "hash": "QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP", @@ -42,9 +42,9 @@ }, { "author": "jbenet", - "hash": "QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D", + "hash": "Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM", "name": "go-datastore", - "version": "3.4.0" + "version": "3.4.1" }, { "author": "hashicorp", @@ -54,9 +54,9 @@ }, { "author": "whyrusleeping", - "hash": "QmTTJcDL3gsnGDALjh2fDGg1onGRUdVgNL2hU2WEZcVrMX", + "hash": "QmPiemjiKBC9VA7vZF82m4x1oygtg2c2YVqag8PX7dN1BD", "name": "go-libp2p-peerstore", - "version": "2.0.6" + "version": "2.0.13" }, { "author": "whyrusleeping", @@ -66,27 +66,27 @@ }, { "author": "whyrusleeping", - "hash": "Qma6ESRQTf1ZLPgzpCwDTqQJefPnU6uLvMjP18vK8EWp8L", + "hash": "QmNvHv84aH2qZafDuSdKJCQ1cvPZ1kmQmyD4YtzjUHuk9v", "name": "go-testutil", - "version": "1.2.10" + "version": "1.2.15" }, { "author": "whyrusleeping", - "hash": "Qma9Eqp16mNHDX1EL73pcxhFfzbyXVcAYtaDd1xdmDRDtL", + "hash": "QmfARXVCzpwFXQdepAJZuqyNDgV9doEsMnVCo1ssmuSe1U", "name": "go-libp2p-record", - "version": "4.1.8" + "version": "4.1.12" }, { "author": "whyrusleeping", - "hash": "QmUmemULEGWabBBZxczWCS3AF9g5jDFcxfMXw9iQkZ3EdD", + "hash": "QmNPEgLVQZeHM7eH5hSfdsTUtgjB1RsndQRFgzHAFkmmC5", "name": "go-libp2p-kbucket", - "version": "2.2.12" + "version": "2.2.18" }, { "author": "whyrusleeping", - "hash": "QmcQ81jSyWCp1jpkQ8CMbtpXT3jK7Wg6ZtYmoyWFgBoF9c", + "hash": "QmTiRqrF5zkdZyrdsL5qndG1UbeWi8k8N2pYxCtXWrahR2", "name": "go-libp2p-routing", - "version": "2.7.1" + "version": "2.7.7" }, { "author": "whyrusleeping", @@ -96,39 +96,39 @@ }, { "author": "whyrusleeping", - "hash": "QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7", + "hash": "QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw", "name": "go-cid", - "version": "0.9.0" + "version": "0.9.1" }, { "author": "whyrusleeping", - "hash": "QmVrDtvvQCUeMZaY9UFkae6c85kdQ1GvVEhPrjPTdjxRLv", + "hash": "QmWZnkipEJbsdUDhgTGBnKAN1iHM2WDMNqsXHyAuaAiCgo", "name": "go-libp2p-loggables", - "version": "1.1.24" + "version": "1.1.29" }, { "author": "whyrusleeping", - "hash": "QmdJfsSbKSZnMkfZ1kpopiyB9i3Hd6cp8VKWZmtWPa7Moc", + "hash": "QmaoXrM4Z41PD48JY36YqQGKQpLGjyLA2cKcLsES7YddAq", "name": "go-libp2p-host", - "version": "3.0.15" + "version": "3.0.21" }, { "author": "whyrusleeping", - "hash": "QmUDTcnDp2WssbmiDLC6aYurUeyt7QeRakHUQMxA2mZ5iB", + "hash": "QmYxivS34F2M2n44WQQnRHGAKS8aoRUxwGpi9wk4Cdn4Jf", "name": "go-libp2p", - "version": "6.0.23" + "version": "6.0.30" }, { "author": "whyrusleeping", - "hash": "QmXuRkCR7BNQa9uqfpTiFWsTQLzmTWYg91Ja1w95gnqb6u", + "hash": "QmNgLg1NTw37iWbYPKcyK85YJ9Whs1MkPtJwhfqbNYAyKg", "name": "go-libp2p-net", - "version": "3.0.15" + "version": "3.0.22" }, { "author": "whyrusleeping", - "hash": "QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A", + "hash": "QmNohiVssaPw3KVLZik59DBVGTSm2dGvYT9eoXt5DQ36Yz", "name": "go-ipfs-util", - "version": "1.2.8" + "version": "1.2.9" }, { "author": "whyrusleeping", @@ -138,9 +138,9 @@ }, { "author": "multiformats", - "hash": "QmT4U94DnD8FRfqr21obWY32HLM5VExccPKMjQHofeYqr9", + "hash": "QmNTCey11oxhb1AxDnQBRHtdhap6Ctud872NjAYPYYXPuc", "name": "go-multiaddr", - "version": "1.3.5" + "version": "1.4.0" }, { "author": "whyrusleeping", @@ -156,9 +156,9 @@ }, { "author": "whyrusleeping", - "hash": "QmVHhT8NxtApPTndiZPe4JNGNUxGWtJe3ebyxtRz4HnbEp", + "hash": "QmegQFxhr1J6yZ1vDQuDmJi5jntmj6BL96S11HVtXNCaHb", "name": "go-libp2p-swarm", - "version": "3.0.22" + "version": "3.0.28" } ], "gxVersion": "0.4.0", @@ -166,6 +166,5 @@ "license": "MIT", "name": "go-libp2p-kad-dht", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "4.4.12" + "version": "4.4.19" } - diff --git a/vendor/github.com/libp2p/go-libp2p-kad-dht/query.go b/vendor/github.com/libp2p/go-libp2p-kad-dht/query.go index 36f8fc1..8794dea 100644 --- a/vendor/github.com/libp2p/go-libp2p-kad-dht/query.go +++ b/vendor/github.com/libp2p/go-libp2p-kad-dht/query.go @@ -1,8 +1,3 @@ -// package query implement a query manager to drive concurrent workers -// to query the DHT. A query is setup with a target key, a queryFunc tasked -// to communicate with a peer, and a set of initial peers. As the query -// progress, queryFunc can return closer peers that will be used to navigate -// closer to the target key in the DHT until an answer is reached. package dht import ( @@ -209,6 +204,8 @@ func (r *dhtQueryRunner) spawnWorkers(proc process.Process) { select { case p, more := <-r.peersToQuery.DeqChan: if !more { + // Put this back so we can finish any outstanding queries. + r.rateLimit <- struct{}{} return // channel closed. } diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index e17a547..404e10c 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -29,6 +29,15 @@ const ( backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) ) +const ( + genericRead = 0x80000000 + genericWrite = 0x40000000 +) + +const ( + consoleTextmodeBuffer = 0x1 +) + type wchar uint16 type short int16 type dword uint32 @@ -69,14 +78,17 @@ var ( procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW") + procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer") ) // Writer provide colorable Writer to the console type Writer struct { - out io.Writer - handle syscall.Handle - oldattr word - oldpos coord + out io.Writer + handle syscall.Handle + althandle syscall.Handle + oldattr word + oldpos coord + rest bytes.Buffer } // NewColorable return new instance of Writer which handle escape sequence from File. @@ -407,7 +419,18 @@ func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - er := bytes.NewReader(data) + handle := w.handle + + var er *bytes.Reader + if w.rest.Len() > 0 { + var rest bytes.Buffer + w.rest.WriteTo(&rest) + w.rest.Reset() + rest.Write(data) + er = bytes.NewReader(rest.Bytes()) + } else { + er = bytes.NewReader(data) + } var bw [1]byte loop: for { @@ -425,29 +448,55 @@ loop: break loop } - if c2 == ']' { - if err := doTitleSequence(er); err != nil { + switch c2 { + case '>': + continue + case ']': + w.rest.WriteByte(c1) + w.rest.WriteByte(c2) + er.WriteTo(&w.rest) + if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 { break loop } + er = bytes.NewReader(w.rest.Bytes()[2:]) + err := doTitleSequence(er) + if err != nil { + break loop + } + w.rest.Reset() continue - } - if c2 != 0x5b { + // https://github.com/mattn/go-colorable/issues/27 + case '7': + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + w.oldpos = csbi.cursorPosition + continue + case '8': + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + continue + case 0x5b: + // execute part after switch + default: continue } + w.rest.WriteByte(c1) + w.rest.WriteByte(c2) + er.WriteTo(&w.rest) + var buf bytes.Buffer var m byte - for { - c, err := er.ReadByte() - if err != nil { - break loop - } + for i, c := range w.rest.Bytes()[2:] { if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { m = c + er = bytes.NewReader(w.rest.Bytes()[2+i+1:]) + w.rest.Reset() break } buf.Write([]byte(string(c))) } + if m == 0 { + break loop + } switch m { case 'A': @@ -455,61 +504,64 @@ loop: if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'B': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'C': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'D': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + if csbi.cursorPosition.x < 0 { + csbi.cursorPosition.x = 0 + } + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'E': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'F': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'G': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = short(n - 1) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'H', 'f': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) if buf.Len() > 0 { token := strings.Split(buf.String(), ";") switch len(token) { @@ -534,7 +586,7 @@ loop: } else { csbi.cursorPosition.y = 0 } - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'J': n := 0 if buf.Len() > 0 { @@ -545,20 +597,20 @@ loop: } var count, written dword var cursor coord - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x) + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x) case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) + count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'K': n := 0 if buf.Len() > 0 { @@ -567,28 +619,28 @@ loop: continue } } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord var count, written dword switch n { case 0: - cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x - 1) + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x) case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} count = dword(csbi.size.x - csbi.cursorPosition.x) case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} count = dword(csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'm': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) attr := csbi.attributes cs := buf.String() if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr)) continue } token := strings.Split(cs, ";") @@ -627,6 +679,21 @@ loop: attr |= n256foreAttr[n256] i += 2 } + } else if len(token) == 5 && token[i+1] == "2" { + var r, g, b int + r, _ = strconv.Atoi(token[i+2]) + g, _ = strconv.Atoi(token[i+3]) + b, _ = strconv.Atoi(token[i+4]) + i += 4 + if r > 127 { + attr |= foregroundRed + } + if g > 127 { + attr |= foregroundGreen + } + if b > 127 { + attr |= foregroundBlue + } } else { attr = attr & (w.oldattr & backgroundMask) } @@ -654,6 +721,21 @@ loop: attr |= n256backAttr[n256] i += 2 } + } else if len(token) == 5 && token[i+1] == "2" { + var r, g, b int + r, _ = strconv.Atoi(token[i+2]) + g, _ = strconv.Atoi(token[i+3]) + b, _ = strconv.Atoi(token[i+4]) + i += 4 + if r > 127 { + attr |= backgroundRed + } + if g > 127 { + attr |= backgroundGreen + } + if b > 127 { + attr |= backgroundBlue + } } else { attr = attr & (w.oldattr & foregroundMask) } @@ -685,38 +767,52 @@ loop: attr |= backgroundBlue } } - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr)) } } case 'h': var ci consoleCursorInfo cs := buf.String() if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?1049" { + if w.althandle == 0 { + h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) + w.althandle = syscall.Handle(h) + if w.althandle != 0 { + handle = w.althandle + } + } } case 'l': var ci consoleCursorInfo cs := buf.String() if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?1049" { + if w.althandle != 0 { + syscall.CloseHandle(w.althandle) + w.althandle = 0 + handle = w.handle + } } case 's': - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.oldpos = csbi.cursorPosition case 'u': - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) } } diff --git a/vendor/github.com/minio/sha256-simd/go.mod b/vendor/github.com/minio/sha256-simd/go.mod new file mode 100644 index 0000000..b68fb0a --- /dev/null +++ b/vendor/github.com/minio/sha256-simd/go.mod @@ -0,0 +1 @@ +module github.com/minio/sha256-simd diff --git a/vendor/github.com/multiformats/go-multicodec/.travis.yml b/vendor/github.com/multiformats/go-multicodec/.travis.yml deleted file mode 100644 index ddf35b2..0000000 --- a/vendor/github.com/multiformats/go-multicodec/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -os: - - linux - -language: go - -go: - - 1.9.x - -install: - - make deps - -script: - - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) - -sudo: false #docker containers for CI - -env: GOTFLAGS="-race -cpu 5" diff --git a/vendor/github.com/multiformats/go-multicodec/LICENSE b/vendor/github.com/multiformats/go-multicodec/LICENSE deleted file mode 100644 index c7386b3..0000000 --- a/vendor/github.com/multiformats/go-multicodec/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Juan Batiz-Benet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-multicodec/Makefile b/vendor/github.com/multiformats/go-multicodec/Makefile deleted file mode 100644 index 2061941..0000000 --- a/vendor/github.com/multiformats/go-multicodec/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -gx: - go get github.com/whyrusleeping/gx - go get github.com/whyrusleeping/gx-go - -deps: gx - gx --verbose install --global - gx-go rewrite - -publish: - gx-go rewrite --undo - diff --git a/vendor/github.com/multiformats/go-multicodec/README.md b/vendor/github.com/multiformats/go-multicodec/README.md deleted file mode 100644 index 2da195a..0000000 --- a/vendor/github.com/multiformats/go-multicodec/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# go-multicodec - -[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) -[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) -[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) -[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) -[![Travis CI](https://img.shields.io/travis/multiformats/go-multicodec.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multicodec) -[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multicodec.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multicodec?branch=master) -[![GoDoc](https://godoc.org/github.com/multiformats/go-multicodec?status.svg)](https://godoc.org/github.com/multiformats/go-multicodec) - -> [multicodec](https://github.com/multiformats/multicodec) implementation in Go. - -### Supported codecs - -- `/cbor` -- `/json` -- `/msgio` -- `/msgpack` -- `/protobuf` - -## Table of Contents - -- [Install](#install) -- [Usage](#usage) -- [Maintainers](#maintainers) -- [Contribute](#contribute) -- [License](#license) - -## Install - -```sh -go get github.com/multiformats/go-multicodec -``` - -## Usage - -Look at the Godocs: - -- https://godoc.org/github.com/multiformats/go-multicodec - -```go -import ( - "os" - "io" - - cbor "github.com/multiformats/go-multicodec/cbor" - json "github.com/multiformats/go-multicodec/json" -) - -func main() { - dec := cbor.Multicodec().Decoder(os.Stdin) - enc := json.Multicodec(false).Encoder(os.Stdout) - - for { - var item interface{} - - if err := dec.Decode(&item); err == io.EOF { - break - } else if err != nil { - panic(err) - } - - if err := enc.Encode(&item); err != nil { - panic(err) - } - } -} -``` - -## Maintainers - -Captain: [@jbenet](https://github.com/jbenet). - -## Contribute - -Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multicodec/issues). - -Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). - -Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. - -## License - -[MIT](LICENSE) © 2014 Juan Batiz-Benet diff --git a/vendor/github.com/multiformats/go-multicodec/coding.go b/vendor/github.com/multiformats/go-multicodec/coding.go deleted file mode 100644 index 46edc16..0000000 --- a/vendor/github.com/multiformats/go-multicodec/coding.go +++ /dev/null @@ -1,55 +0,0 @@ -package multicodec - -import ( - "bytes" - "io" -) - -// Codec is an algorithm for coding data from one representation -// to another. For convenience, we define a codec in the usual -// sense: a function and its inverse, to encode and decode. -type Codec interface { - // Decoder wraps given io.Reader and returns an object which - // will decode bytes into objects. - Decoder(r io.Reader) Decoder - - // Encoder wraps given io.Writer and returns an Encoder - Encoder(w io.Writer) Encoder -} - -// Encoder encodes objects into bytes and writes them to an -// underlying io.Writer. Works like encoding.Marshal -type Encoder interface { - Encode(n interface{}) error -} - -// Decoder decodes objects from bytes from an underlying -// io.Reader, into given object. Works like encoding.Unmarshal -type Decoder interface { - Decode(n interface{}) error -} - -// Marshal serializes an object to a []byte. -func Marshal(c Codec, o interface{}) ([]byte, error) { - var buf bytes.Buffer - err := MarshalTo(c, &buf, o) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// MarshalTo serializes an object to a writer. -func MarshalTo(c Codec, w io.Writer, o interface{}) error { - return c.Encoder(w).Encode(o) -} - -// Unmarshal deserializes an object to a []byte. -func Unmarshal(c Codec, buf []byte, o interface{}) error { - return UnmarshalFrom(c, bytes.NewBuffer(buf), o) -} - -// UnmarshalFrom deserializes an objects from a reader. -func UnmarshalFrom(c Codec, r io.Reader, o interface{}) error { - return c.Decoder(r).Decode(o) -} diff --git a/vendor/github.com/multiformats/go-multicodec/header.go b/vendor/github.com/multiformats/go-multicodec/header.go deleted file mode 100644 index faa4769..0000000 --- a/vendor/github.com/multiformats/go-multicodec/header.go +++ /dev/null @@ -1,140 +0,0 @@ -package multicodec - -import ( - "bufio" - "bytes" - "errors" - "io" -) - -var ( - ErrType = errors.New("multicodec type error") - ErrHeaderInvalid = errors.New("multicodec header invalid") - ErrMismatch = errors.New("multicodec did not match") - ErrVarints = errors.New("multicodec varints not yet implemented") -) - -// Header returns a multicodec header with the given path. -func Header(path []byte) []byte { - b, err := HeaderSafe(path) - if err != nil { - panic(err.Error) - } - return b -} - -// HeaderSafe works like Header but it returns error instead of calling panic -func HeaderSafe(path []byte) ([]byte, error) { - l := len(path) + 1 // + \n - if l >= 127 { - return nil, ErrVarints - } - - buf := make([]byte, l+1) - buf[0] = byte(l) - copy(buf[1:], path) - buf[l] = '\n' - return buf, nil -} - -// HeaderPath returns the multicodec path from header -func HeaderPath(hdr []byte) []byte { - hdr = hdr[1:] - if hdr[len(hdr)-1] == '\n' { - hdr = hdr[:len(hdr)-1] - } - return hdr -} - -// WriteHeader writes a multicodec header to a writer. -// It uses the given path. -func WriteHeader(w io.Writer, path []byte) error { - hdr := Header(path) - _, err := w.Write(hdr) - return err -} - -// ReadHeader reads a multicodec header from a reader. -// Returns the header found, or an error if the header -// mismatched. -func ReadHeader(r io.Reader) (path []byte, err error) { - lbuf := make([]byte, 1) - if _, err := r.Read(lbuf); err != nil { - return nil, err - } - - l := int(lbuf[0]) - if l > 127 { - return nil, ErrVarints - } - - buf := make([]byte, l+1) - buf[0] = lbuf[0] - if _, err := io.ReadFull(r, buf[1:]); err != nil { - return nil, err - } - if buf[l] != '\n' { - return nil, ErrHeaderInvalid - } - return buf, nil -} - -// ReadPath reads a multicodec header from a reader. -// Returns the path found, or an error if the header -// mismatched. -func ReadPath(r io.Reader) (path []byte, err error) { - hdr, err := ReadHeader(r) - if err != nil { - return nil, err - } - return HeaderPath(hdr), nil -} - -// ConsumePath reads a multicodec header from a reader, -// verifying it matches given path. If it does not, it returns -// ErrProtocolMismatch -func ConsumePath(r io.Reader, path []byte) (err error) { - actual, err := ReadPath(r) - if !bytes.Equal(path, actual) { - return ErrMismatch - } - return nil -} - -// ConsumeHeader reads a multicodec header from a reader, -// verifying it matches given header. If it does not, it returns -// ErrProtocolMismatch -func ConsumeHeader(r io.Reader, header []byte) (err error) { - actual := make([]byte, len(header)) - if _, err := io.ReadFull(r, actual); err != nil { - return err - } - - if !bytes.Equal(header, actual) { - return ErrMismatch - } - return nil -} - -// WrapHeaderReader returns a reader that first reads the -// given header, and then the given reader, using io.MultiReader. -// It is useful if the header has been read through, but still -// needed to pass to a decoder. -func WrapHeaderReader(hdr []byte, r io.Reader) io.Reader { - return io.MultiReader(bytes.NewReader(hdr), r) -} - -func WrapTransformPathToHeader(r io.Reader) (io.Reader, error) { - br := bufio.NewReader(r) - - p, err := br.ReadBytes('\n') - if err != nil { - return nil, err - } - p = p[:len(p)-1] // drop newline - hdr, err := HeaderSafe(p) - if err != nil { - return nil, err - } - return WrapHeaderReader(hdr, br), nil -} diff --git a/vendor/github.com/multiformats/go-multicodec/msgpack/msgpack.go b/vendor/github.com/multiformats/go-multicodec/msgpack/msgpack.go deleted file mode 100644 index 0db1173..0000000 --- a/vendor/github.com/multiformats/go-multicodec/msgpack/msgpack.go +++ /dev/null @@ -1,87 +0,0 @@ -package mc_msgpack - -import ( - "io" - - mc "github.com/multiformats/go-multicodec" - gocodec "github.com/ugorji/go/codec" -) - -const HeaderPath = "/msgpack" - -var Header = mc.Header([]byte(HeaderPath)) - -type codec struct { - mc bool - handle *gocodec.MsgpackHandle -} - -func Codec(h *gocodec.MsgpackHandle) mc.Codec { - return &codec{ - mc: false, - handle: h, - } -} - -func DefaultMsgpackHandle() *gocodec.MsgpackHandle { - return &gocodec.MsgpackHandle{} -} - -func Multicodec(h *gocodec.MsgpackHandle) mc.Multicodec { - return &codec{ - mc: true, - handle: h, - } -} - -func (c *codec) Encoder(w io.Writer) mc.Encoder { - return &encoder{ - w: w, - mc: c.mc, - enc: gocodec.NewEncoder(w, c.handle), - } -} - -func (c *codec) Decoder(r io.Reader) mc.Decoder { - return &decoder{ - r: r, - mc: c.mc, - dec: gocodec.NewDecoder(r, c.handle), - } -} - -func (c *codec) Header() []byte { - return Header -} - -type encoder struct { - w io.Writer - mc bool - enc *gocodec.Encoder -} - -type decoder struct { - r io.Reader - mc bool - dec *gocodec.Decoder -} - -func (c *encoder) Encode(v interface{}) error { - // if multicodec, write the header first - if c.mc { - if _, err := c.w.Write(Header); err != nil { - return err - } - } - return c.enc.Encode(v) -} - -func (c *decoder) Decode(v interface{}) error { - // if multicodec, consume the header first - if c.mc { - if err := mc.ConsumeHeader(c.r, Header); err != nil { - return err - } - } - return c.dec.Decode(v) -} diff --git a/vendor/github.com/multiformats/go-multicodec/multicodec.go b/vendor/github.com/multiformats/go-multicodec/multicodec.go deleted file mode 100644 index 72a1d2f..0000000 --- a/vendor/github.com/multiformats/go-multicodec/multicodec.go +++ /dev/null @@ -1,70 +0,0 @@ -package multicodec - -import "io" - -// Multicodec is the interface for a multicodec -type Multicodec interface { - Codec - - Header() []byte -} - -type c2mc struct { - c Codec - header []byte -} - -var _ Multicodec = (*c2mc)(nil) - -func (c c2mc) Header() []byte { - return c.header -} - -type c2mcD struct { - base *c2mc - r io.Reader -} - -func (d c2mcD) Decode(v interface{}) error { - err := ConsumeHeader(d.r, d.base.header) - if err != nil { - return err - } - return d.base.c.Decoder(d.r).Decode(v) -} - -var _ Decoder = (*c2mcD)(nil) - -func (c c2mc) Decoder(r io.Reader) Decoder { - return c2mcD{ - base: &c, - r: r, - } -} - -type c2mcE struct { - base *c2mc - w io.Writer -} - -func (e c2mcE) Encode(v interface{}) error { - _, err := e.w.Write(e.base.Header()) - if err != nil { - return err - } - return e.base.c.Encoder(e.w).Encode(v) -} - -func (c c2mc) Encoder(w io.Writer) Encoder { - return c2mcE{ - base: &c, - w: w, - } -} - -func NewMulticodecFromCodec(c Codec, header []byte) Multicodec { - return c2mc{ - c: c, - header: header, - } -} diff --git a/vendor/github.com/multiformats/go-multicodec/package.json b/vendor/github.com/multiformats/go-multicodec/package.json deleted file mode 100644 index ecfc477..0000000 --- a/vendor/github.com/multiformats/go-multicodec/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "author": "multiformats", - "bugs": { - "url": "https://github.com/multiformats/go-multicodec/issues" - }, - "gx": { - "dvcsimport": "github.com/multiformats/go-multicodec" - }, - "gxDependencies": [ - { - "author": "whyrusleeping", - "hash": "QmWBug6eBS7AxRdCDVuSY5CnSit7cS2XnPFYJWqWDumhCG", - "name": "go-msgio", - "version": "0.0.3" - }, - { - "author": "whyrusleeping", - "hash": "QmcRKRQjNc2JZPHApR32fbkZVd6WXG2Ch9Kcy7sPxuAJgd", - "name": "cbor", - "version": "0.2.3" - }, - { - "author": "ugorji", - "hash": "QmVTAmbCaPqdfbmpWDCJMQNFxbyJoG2USFsumXmTWY5LFp", - "name": "go-codec", - "version": "2017.10.18" - }, - { - "author": "whyrusleeping", - "hash": "QmdxUuburamoF6zF9qjeQC4WYcWGbWuRmdLacMEsW8ioD8", - "name": "gogo-protobuf", - "version": "0.0.0" - } - ], - "gxVersion": "0.10.0", - "language": "go", - "license": "MIT", - "name": "go-multicodec", - "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "0.1.6" -} - diff --git a/vendor/github.com/multiformats/go-multihash/.travis.yml b/vendor/github.com/multiformats/go-multihash/.travis.yml index 25711d6..9f10ab5 100644 --- a/vendor/github.com/multiformats/go-multihash/.travis.yml +++ b/vendor/github.com/multiformats/go-multihash/.travis.yml @@ -1,12 +1,10 @@ os: - linux -sudo: false - language: go go: - - 1.9.x + - 1.11.x install: - make deps diff --git a/vendor/github.com/multiformats/go-multihash/README.md b/vendor/github.com/multiformats/go-multihash/README.md index 318974a..dd7f238 100644 --- a/vendor/github.com/multiformats/go-multihash/README.md +++ b/vendor/github.com/multiformats/go-multihash/README.md @@ -26,25 +26,8 @@ go get github.com/multiformats/go-multihash ``` -Note that `go-multihash` is packaged with Gx, so it is recommended to use Gx to install and use it (see Usage section). - ## Usage -### Using Gx and Gx-go - -This module is packaged with [Gx](https://github.com/whyrusleeping/gx). In order to use it in your own project it is recommended that you: - -```sh -go get -u github.com/whyrusleeping/gx -go get -u github.com/whyrusleeping/gx-go -cd -gx init -gx import github.com/multiformats/go-multihash -gx install --global -gx-go --rewrite -``` - -Please check [Gx](https://github.com/whyrusleeping/gx) and [Gx-go](https://github.com/whyrusleeping/gx-go) documentation for more information. ### Example @@ -94,10 +77,6 @@ hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 ``` -## Maintainers - -Captain: [@Kubuxu](https://github.com/Kubuxu). - ## Contribute Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multihash/issues). diff --git a/vendor/github.com/multiformats/go-multihash/go.mod b/vendor/github.com/multiformats/go-multihash/go.mod new file mode 100644 index 0000000..79a1dfc --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/go.mod @@ -0,0 +1,11 @@ +module github.com/multiformats/go-multihash + +require ( + github.com/gxed/hashland/keccakpg v0.0.1 + github.com/gxed/hashland/murmur3 v0.0.1 + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 + github.com/mr-tron/base58 v1.1.0 + golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 + golang.org/x/sys v0.0.0-20190219092855-153ac476189d // indirect +) diff --git a/vendor/github.com/multiformats/go-multihash/go.sum b/vendor/github.com/multiformats/go-multihash/go.sum new file mode 100644 index 0000000..ecd77b6 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/go.sum @@ -0,0 +1,14 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/multiformats/go-multihash/multihash.go b/vendor/github.com/multiformats/go-multihash/multihash.go index 92b4fda..8c5efbf 100644 --- a/vendor/github.com/multiformats/go-multihash/multihash.go +++ b/vendor/github.com/multiformats/go-multihash/multihash.go @@ -61,6 +61,8 @@ const ( DBL_SHA2_256 = 0x56 MURMUR3 = 0x22 + + X11 = 0x1100 ) func init() { @@ -102,6 +104,7 @@ var Names = map[string]uint64{ "keccak-512": KECCAK_512, "shake-128": SHAKE_128, "shake-256": SHAKE_256, + "x11": X11, } // Codes maps a hash code to it's name @@ -122,6 +125,7 @@ var Codes = map[uint64]string{ KECCAK_512: "keccak-512", SHAKE_128: "shake-128", SHAKE_256: "shake-256", + X11: "x11", } // DefaultLengths maps a hash code to it's default length @@ -142,6 +146,7 @@ var DefaultLengths = map[uint64]int{ KECCAK_512: 64, SHAKE_128: 32, SHAKE_256: 64, + X11: 64, } func uvarint(buf []byte) (uint64, []byte, error) { @@ -266,7 +271,7 @@ func Encode(buf []byte, code uint64) ([]byte, error) { return nil, ErrUnknownCode } - start := make([]byte, 2*binary.MaxVarintLen64) + start := make([]byte, 2*binary.MaxVarintLen64, 2*binary.MaxVarintLen64+len(buf)) spot := start n := binary.PutUvarint(spot, code) spot = start[n:] @@ -283,18 +288,6 @@ func EncodeName(buf []byte, name string) ([]byte, error) { // ValidCode checks whether a multihash code is valid. func ValidCode(code uint64) 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 uint64) bool { - return code >= 0 && code < 0x10 + _, ok := Codes[code] + return ok } diff --git a/vendor/github.com/multiformats/go-multihash/package.json b/vendor/github.com/multiformats/go-multihash/package.json index 279ecd4..af15ff5 100644 --- a/vendor/github.com/multiformats/go-multihash/package.json +++ b/vendor/github.com/multiformats/go-multihash/package.json @@ -25,23 +25,23 @@ "name": "keccakpg", "version": "0.0.1" }, - { - "author": "whyrusleeping", - "hash": "QmfJHywXQu98UeZtGJBQrPAR6AtmDjjbe3qjTo9piXHPnx", - "name": "murmur3", - "version": "0.0.0" - }, { "author": "minio", - "hash": "QmXTpwq2AkzQsPjKqFQDNY2bMdsAT53hUBETeyj8QRHTZU", + "hash": "QmcTzQXRcU2vf8yX5EEboz1BSvWC7wWmeYAKVQmhp8WZYU", "name": "sha256-simd", - "version": "0.1.1" + "version": "0.1.2" }, { "author": "minio", "hash": "QmZp3eKdYQHHAneECmeK6HhiMwTPufmjC8DuuaGKv3unvx", "name": "blake2b-simd", "version": "0.1.1" + }, + { + "author": "whyrusleeping", + "hash": "QmWAXZgFyppTRshtnVHJ8LnA1yoHjUr41ZnsWPoA8wnSgF", + "name": "hashland-murmur3", + "version": "0.0.1" } ], "gxVersion": "0.9.0", @@ -49,6 +49,6 @@ "license": "MIT", "name": "go-multihash", "releaseCmd": "git commit -a -m \"gx release $VERSION\"", - "version": "1.0.8" + "version": "1.0.10" } diff --git a/vendor/github.com/multiformats/go-multihash/sum.go b/vendor/github.com/multiformats/go-multihash/sum.go index af3f079..5301e0d 100644 --- a/vendor/github.com/multiformats/go-multihash/sum.go +++ b/vendor/github.com/multiformats/go-multihash/sum.go @@ -7,9 +7,9 @@ import ( "fmt" keccak "github.com/gxed/hashland/keccakpg" + murmur3 "github.com/gxed/hashland/murmur3" blake2b "github.com/minio/blake2b-simd" sha256 "github.com/minio/sha256-simd" - murmur3 "github.com/spaolacci/murmur3" blake2s "golang.org/x/crypto/blake2s" sha3 "golang.org/x/crypto/sha3" ) @@ -17,78 +17,41 @@ import ( // ErrSumNotSupported is returned when the Sum function code is not implemented var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.") +// HashFunc is a hash function that hashes data into digest. +// +// The length is the size the digest will be truncated to. While the hash +// function isn't responsible for truncating the digest, it may want to error if +// the length is invalid for the hash function (e.g., truncation would make the +// hash useless). +type HashFunc func(data []byte, length int) (digest []byte, err error) + +// funcTable maps multicodec values to hash functions. +var funcTable = make(map[uint64]HashFunc) + // Sum obtains the cryptographic sum of a given buffer. The length parameter // indicates the length of the resulting digest and passing a negative value // use default length values for the selected hash function. func Sum(data []byte, code uint64, length int) (Multihash, error) { - m := Multihash{} - err := error(nil) if !ValidCode(code) { - return m, fmt.Errorf("invalid multihash code %d", code) + return nil, fmt.Errorf("invalid multihash code %d", code) } if length < 0 { var ok bool length, ok = DefaultLengths[code] if !ok { - return m, fmt.Errorf("no default length for code %d", code) + return nil, fmt.Errorf("no default length for code %d", code) } } - var d []byte - switch { - case isBlake2s(code): - olen := code - BLAKE2S_MIN + 1 - switch olen { - case 32: - out := blake2s.Sum256(data) - d = out[:] - default: - return nil, fmt.Errorf("unsupported length for blake2s: %d", olen) - } - case isBlake2b(code): - olen := uint8(code - BLAKE2B_MIN + 1) - d = sumBlake2b(olen, data) - default: - switch code { - case ID: - d, err = sumID(data, length) - case SHA1: - d = sumSHA1(data) - case SHA2_256: - d = sumSHA256(data) - case SHA2_512: - d = sumSHA512(data) - case KECCAK_224: - d = sumKeccak224(data) - case KECCAK_256: - d = sumKeccak256(data) - case KECCAK_384: - d = sumKeccak384(data) - case KECCAK_512: - d = sumKeccak512(data) - case SHA3_224: - d = sumSHA3_224(data) - case SHA3_256: - d = sumSHA3_256(data) - case SHA3_384: - d = sumSHA3_384(data) - case SHA3_512: - d = sumSHA3_512(data) - case DBL_SHA2_256: - d = sumSHA256(sumSHA256(data)) - case MURMUR3: - d, err = sumMURMUR3(data) - case SHAKE_128: - d = sumSHAKE128(data) - case SHAKE_256: - d = sumSHAKE256(data) - default: - return m, ErrSumNotSupported - } + hashFunc, ok := funcTable[code] + if !ok { + return nil, ErrSumNotSupported } + + d, err := hashFunc(data, length) if err != nil { - return m, err + return nil, err } if length >= 0 { d = d[:length] @@ -96,24 +59,24 @@ func Sum(data []byte, code uint64, length int) (Multihash, error) { return Encode(d, code) } -func isBlake2s(code uint64) bool { - return code >= BLAKE2S_MIN && code <= BLAKE2S_MAX -} -func isBlake2b(code uint64) bool { - return code >= BLAKE2B_MIN && code <= BLAKE2B_MAX +func sumBlake2s(data []byte, size int) ([]byte, error) { + if size != 32 { + return nil, fmt.Errorf("unsupported length for blake2s: %d", size) + } + d := blake2s.Sum256(data) + return d[:], nil } - -func sumBlake2b(size uint8, data []byte) []byte { - hasher, err := blake2b.New(&blake2b.Config{Size: size}) +func sumBlake2b(data []byte, size int) ([]byte, error) { + hasher, err := blake2b.New(&blake2b.Config{Size: uint8(size)}) if err != nil { - panic(err) + return nil, err } if _, err := hasher.Write(data); err != nil { - panic(err) + return nil, err } - return hasher.Sum(nil)[:] + return hasher.Sum(nil)[:], nil } func sumID(data []byte, length int) ([]byte, error) { @@ -125,59 +88,56 @@ func sumID(data []byte, length int) ([]byte, error) { return data, nil } -func sumSHA1(data []byte) []byte { +func sumSHA1(data []byte, length int) ([]byte, error) { a := sha1.Sum(data) - return a[0:20] + return a[0:20], nil } -func sumSHA256(data []byte) []byte { +func sumSHA256(data []byte, length int) ([]byte, error) { a := sha256.Sum256(data) - return a[0:32] + return a[0:32], nil } -func sumSHA512(data []byte) []byte { +func sumDoubleSHA256(data []byte, length int) ([]byte, error) { + val, _ := sumSHA256(data, len(data)) + return sumSHA256(val, len(val)) +} + +func sumSHA512(data []byte, length int) ([]byte, error) { a := sha512.Sum512(data) - return a[0:64] + return a[0:64], nil } -func sumKeccak224(data []byte) []byte { +func sumKeccak224(data []byte, length int) ([]byte, error) { h := keccak.New224() h.Write(data) - return h.Sum(nil) + return h.Sum(nil), nil } -func sumKeccak256(data []byte) []byte { +func sumKeccak256(data []byte, length int) ([]byte, error) { h := keccak.New256() h.Write(data) - return h.Sum(nil) + return h.Sum(nil), nil } -func sumKeccak384(data []byte) []byte { +func sumKeccak384(data []byte, length int) ([]byte, error) { h := keccak.New384() h.Write(data) - return h.Sum(nil) + return h.Sum(nil), nil } -func sumKeccak512(data []byte) []byte { +func sumKeccak512(data []byte, length int) ([]byte, error) { h := keccak.New512() h.Write(data) - return h.Sum(nil) -} - -func sumSHA3(data []byte) ([]byte, error) { - h := sha3.New512() - if _, err := h.Write(data); err != nil { - return nil, err - } return h.Sum(nil), nil } -func sumSHA3_512(data []byte) []byte { +func sumSHA3_512(data []byte, length int) ([]byte, error) { a := sha3.Sum512(data) - return a[:] + return a[:], nil } -func sumMURMUR3(data []byte) ([]byte, error) { +func sumMURMUR3(data []byte, length int) ([]byte, error) { number := murmur3.Sum32(data) bytes := make([]byte, 4) for i := range bytes { @@ -187,29 +147,93 @@ func sumMURMUR3(data []byte) ([]byte, error) { return bytes, nil } -func sumSHAKE128(data []byte) []byte { +func sumSHAKE128(data []byte, length int) ([]byte, error) { bytes := make([]byte, 32) sha3.ShakeSum128(bytes, data) - return bytes + return bytes, nil } -func sumSHAKE256(data []byte) []byte { +func sumSHAKE256(data []byte, length int) ([]byte, error) { bytes := make([]byte, 64) sha3.ShakeSum256(bytes, data) - return bytes + return bytes, nil } -func sumSHA3_384(data []byte) []byte { +func sumSHA3_384(data []byte, length int) ([]byte, error) { a := sha3.Sum384(data) - return a[:] + return a[:], nil } -func sumSHA3_256(data []byte) []byte { +func sumSHA3_256(data []byte, length int) ([]byte, error) { a := sha3.Sum256(data) - return a[:] + return a[:], nil } -func sumSHA3_224(data []byte) []byte { +func sumSHA3_224(data []byte, length int) ([]byte, error) { a := sha3.Sum224(data) - return a[:] + return a[:], nil +} + +func registerStdlibHashFuncs() { + RegisterHashFunc(ID, sumID) + RegisterHashFunc(SHA1, sumSHA1) + RegisterHashFunc(SHA2_512, sumSHA512) +} + +func registerNonStdlibHashFuncs() { + RegisterHashFunc(SHA2_256, sumSHA256) + RegisterHashFunc(DBL_SHA2_256, sumDoubleSHA256) + + RegisterHashFunc(KECCAK_224, sumKeccak224) + RegisterHashFunc(KECCAK_256, sumKeccak256) + RegisterHashFunc(KECCAK_384, sumKeccak384) + RegisterHashFunc(KECCAK_512, sumKeccak512) + + RegisterHashFunc(SHA3_224, sumSHA3_224) + RegisterHashFunc(SHA3_256, sumSHA3_256) + RegisterHashFunc(SHA3_384, sumSHA3_384) + RegisterHashFunc(SHA3_512, sumSHA3_512) + + RegisterHashFunc(MURMUR3, sumMURMUR3) + + RegisterHashFunc(SHAKE_128, sumSHAKE128) + RegisterHashFunc(SHAKE_256, sumSHAKE256) + + // Blake family of hash functions + // BLAKE2S + for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ { + size := int(c - BLAKE2S_MIN + 1) + RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) { + return sumBlake2s(buf, size) + }) + } + // BLAKE2B + for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ { + size := int(c - BLAKE2B_MIN + 1) + RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) { + return sumBlake2b(buf, size) + }) + } +} + +func init() { + registerStdlibHashFuncs() + registerNonStdlibHashFuncs() +} + +// RegisterHashFunc adds an entry to the package-level code -> hash func map. +// The hash function must return at least the requested number of bytes. If it +// returns more, the hash will be truncated. +func RegisterHashFunc(code uint64, hashFunc HashFunc) error { + if !ValidCode(code) { + return fmt.Errorf("code %v not valid", code) + } + + _, ok := funcTable[code] + if ok { + return fmt.Errorf("hash func for code %v already registered", code) + } + + funcTable[code] = hashFunc + return nil } diff --git a/vendor/github.com/perlin-network/life/compiler/module.go b/vendor/github.com/perlin-network/life/compiler/module.go index fca5a39..1ef5675 100644 --- a/vendor/github.com/perlin-network/life/compiler/module.go +++ b/vendor/github.com/perlin-network/life/compiler/module.go @@ -10,6 +10,7 @@ import ( "github.com/go-interpreter/wagon/wasm/leb128" "github.com/perlin-network/life/compiler/opcodes" "github.com/perlin-network/life/utils" + "strings" ) type Module struct { @@ -103,6 +104,73 @@ func LoadModule(raw []byte) (*Module, error) { }, nil } +func (m *Module) CompileWithNGen(gp GasPolicy, numGlobals uint64) (out string, retErr error) { + defer utils.CatchPanic(&retErr) + + importStubBuilder := &strings.Builder{} + importTypeIDs := make([]int, 0) + numFuncImports := 0 + + if m.Base.Import != nil { + for i := 0; i < len(m.Base.Import.Entries); i++ { + e := &m.Base.Import.Entries[i] + if e.Type.Kind() != wasm.ExternalFunction { + continue + } + tyID := e.Type.(wasm.FuncImport).Type + ty := &m.Base.Types.Entries[int(tyID)] + + bSprintf(importStubBuilder, "uint64_t %s%d(struct VirtualMachine *vm", NGEN_FUNCTION_PREFIX, i) + for j := 0; j < len(ty.ParamTypes); j++ { + bSprintf(importStubBuilder, ",uint64_t %s%d", NGEN_LOCAL_PREFIX, j) + } + importStubBuilder.WriteString(") {\n") + importStubBuilder.WriteString("uint64_t params[] = {") + for j := 0; j < len(ty.ParamTypes); j++ { + bSprintf(importStubBuilder, "%s%d", NGEN_LOCAL_PREFIX, j) + if j != len(ty.ParamTypes)-1 { + importStubBuilder.WriteByte(',') + } + } + importStubBuilder.WriteString("};\n") + bSprintf(importStubBuilder, "return %sinvoke_import(vm, %d, %d, params);\n", NGEN_ENV_API_PREFIX, numFuncImports, len(ty.ParamTypes)) + importStubBuilder.WriteString("}\n") + importTypeIDs = append(importTypeIDs, int(tyID)) + numFuncImports++ + } + } + + out += importStubBuilder.String() + + for i, f := range m.Base.FunctionIndexSpace { + //fmt.Printf("Compiling function %d (%+v) with %d locals\n", i, f.Sig, len(f.Body.Locals)) + d, err := disasm.Disassemble(f, m.Base) + if err != nil { + panic(err) + } + compiler := NewSSAFunctionCompiler(m.Base, d) + compiler.CallIndexOffset = numFuncImports + compiler.Compile(importTypeIDs) + if m.DisableFloatingPoint { + compiler.FilterFloatingPoint() + } + if gp != nil { + compiler.InsertGasCounters(gp) + } + //fmt.Println(compiler.Code) + //fmt.Printf("%+v\n", compiler.NewCFGraph()) + //numRegs := compiler.RegAlloc() + //fmt.Println(compiler.Code) + numLocals := 0 + for _, v := range f.Body.Locals { + numLocals += int(v.Count) + } + out += compiler.NGen(uint64(numFuncImports+i), uint64(len(f.Sig.ParamTypes)), uint64(numLocals), numGlobals) + } + + return +} + func (m *Module) CompileForInterpreter(gp GasPolicy) (_retCode []InterpreterCode, retErr error) { defer utils.CatchPanic(&retErr) diff --git a/vendor/github.com/perlin-network/life/compiler/ngen.go b/vendor/github.com/perlin-network/life/compiler/ngen.go new file mode 100644 index 0000000..f1603f4 --- /dev/null +++ b/vendor/github.com/perlin-network/life/compiler/ngen.go @@ -0,0 +1,688 @@ +package compiler + +import ( + "fmt" + "strings" +) + +const NGEN_FUNCTION_PREFIX = "wasm_function_" +const NGEN_LOCAL_PREFIX = "l" +const NGEN_VALUE_PREFIX = "v" +const NGEN_INS_LABEL_PREFIX = "ins" +const NGEN_ENV_API_PREFIX = "wenv_" +const NGEN_HEADER = ` +//static const uint64_t UINT32_MASK = 0xffffffffull; +struct VirtualMachine; +typedef uint64_t (*ExternalFunction)(struct VirtualMachine *vm, uint64_t import_id, uint64_t num_params, uint64_t *params); +struct VirtualMachine { + void (*throw_s)(struct VirtualMachine *vm, const char *s); + ExternalFunction (*resolve_import)(struct VirtualMachine *vm, const char *module_name, const char *field_name); + uint64_t mem_size; + uint8_t *mem; + void (*grow_memory)(struct VirtualMachine *vm, uint64_t inc_size); + void *userdata; +}; + +#define V_uint32_t vu32 +#define V_uint64_t vu64 +#define V_int32_t vi32 +#define V_int64_t vi64 +#define V_float vf32 +#define V_double vf64 + +union Value { + uint32_t vu32; + uint64_t vu64; + int32_t vi32; + int64_t vi64; + float vf32; + double vf64; +}; +static uint8_t * __attribute__((always_inline)) mem_translate(struct VirtualMachine *vm, union Value start, uint32_t offset, uint32_t size) { + start.vu32 += offset; + #ifndef POLYMERASE_NO_MEM_BOUND_CHECK + if(start.vu32 + size < start.vu32 || start.vu32 + size > vm->mem_size) vm->throw_s(vm, "memory access out of bounds"); + #endif + return &vm->mem[start.vu32]; +} +static uint64_t __attribute__((always_inline)) clz32(uint32_t x) { + return __builtin_clz(x); +} +static uint64_t __attribute__((always_inline)) ctz32(uint32_t x) { + return __builtin_ctz(x); +} +static uint64_t __attribute__((always_inline)) clz64(uint64_t x) { + return __builtin_clzll(x); +} +static uint64_t __attribute__((always_inline)) ctz64(uint64_t x) { + return __builtin_ctzll(x); +} +static uint64_t __attribute__((always_inline)) rotl32( uint32_t x, uint32_t r ) +{ + return (x << r) | (x >> (32 - r % 32)); +} +static uint64_t __attribute__((always_inline)) rotl64( uint64_t x, uint64_t r ) +{ + return (x << r) | (x >> (64 - r % 64)); +} +static uint64_t __attribute__((always_inline)) rotr32( uint32_t x, uint32_t r ) +{ + return (x >> r) | (x << (32 - r % 32)); +} +static uint64_t __attribute__((always_inline)) rotr64( uint64_t x, uint64_t r ) +{ + return (x >> r) | (x << (64 - r % 64)); +} +` +const NGEN_FP_HEADER = ` +#include + +static float __attribute__((always_inline)) fmin32(float a, float b) { + if(isnan(a) || isnan(b)) return NAN; + return fminf(a, b); +} + +static double __attribute__((always_inline)) fmin64(double a, double b) { + if(isnan(a) || isnan(b)) return NAN; + return fmin(a, b); +} + +static float __attribute__((always_inline)) fmax32(float a, float b) { + if(isnan(a) || isnan(b)) return NAN; + return fmaxf(a, b); +} + +static double __attribute__((always_inline)) fmax64(double a, double b) { + if(isnan(a) || isnan(b)) return NAN; + return fmax(a, b); +} + +static float __attribute__((always_inline)) fneg32(float x) { + return -x; +} + +static double __attribute__((always_inline)) fneg64(double x) { + return -x; +} + +#define fsqrt32 sqrtf +#define fsqrt64 sqrt +#define fceil32 ceilf +#define fceil64 ceil +#define ffloor32 floorf +#define ffloor64 floor +#define ftrunc32 truncf +#define ftrunc64 trunc +#define fnearest32 roundf +#define fnearest64 round +#define fabs32 fabsf +#define fabs64 fabs +#define fcopysign32 copysignf +#define fcopysign64 copysign +` + +func bSprintf(builder *strings.Builder, format string, args ...interface{}) { + builder.WriteString(fmt.Sprintf(format, args...)) +} + +func writeDivZeroRvCheck(b *strings.Builder, ins Instr) { + bSprintf(b, "if(%s%d.vu64 == 0) vm->throw_s(vm, \"divide by zero\"); ", NGEN_VALUE_PREFIX, ins.Values[1]) // TODO: fix +} + +func writeUnOp_Eqz(b *strings.Builder, ins Instr, ty string) { + bSprintf(b, + "%s%d.vu64 = (%s%d.V_%s == 0);", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + ) +} + +func writeUnOp_Fcall(b *strings.Builder, ins Instr, f string, ty string, retTy string) { + bSprintf(b, + "%s%d.V_%s = %s(%s%d.V_%s);", + NGEN_VALUE_PREFIX, ins.Target, retTy, + f, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + ) +} + +func writeBinOp_Shift(b *strings.Builder, ins Instr, op string, ty string, rounding uint64) { + bSprintf(b, + "%s%d.vu64 = (%s%d.V_%s) %s (%s%d.V_%s %% %d);", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + op, + NGEN_VALUE_PREFIX, ins.Values[1], ty, + rounding, + ) +} + +func writeBinOp_Fcall(b *strings.Builder, ins Instr, f string, ty string, retTy string) { + bSprintf(b, + "%s%d.V_%s = %s(%s%d.V_%s, %s%d.V_%s);", + NGEN_VALUE_PREFIX, ins.Target, retTy, + f, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + NGEN_VALUE_PREFIX, ins.Values[1], ty, + ) +} + +func writeBinOp_ConstRv(b *strings.Builder, ins Instr, op string, ty string, rv string) { + bSprintf(b, + "%s%d.V_%s = (%s%d.V_%s %s (%s));", + NGEN_VALUE_PREFIX, ins.Target, ty, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + op, + rv, + ) +} + +func writeBinOp2(b *strings.Builder, ins Instr, op string, ty string, retTy string) { + bSprintf(b, + "%s%d.V_%s = (%s%d.V_%s %s %s%d.V_%s);", + NGEN_VALUE_PREFIX, ins.Target, retTy, + NGEN_VALUE_PREFIX, ins.Values[0], ty, + op, + NGEN_VALUE_PREFIX, ins.Values[1], ty, + ) +} + +func writeBinOp(b *strings.Builder, ins Instr, op string, ty string) { + writeBinOp2(b, ins, op, ty, ty) +} + +func writeMemLoad(b *strings.Builder, ins Instr, ty string) { + bSprintf(b, + "%s%d.vi64 = * (%s *) mem_translate(vm, %s%d, %du, sizeof(%s));", // TODO: any missing conversions? + NGEN_VALUE_PREFIX, ins.Target, + ty, + NGEN_VALUE_PREFIX, ins.Values[0], + uint64(ins.Immediates[1]), + ty, + ) +} + +func writeMemStore(b *strings.Builder, ins Instr, ty string) { + bSprintf(b, + "* (%s *) mem_translate(vm, %s%d, %du, sizeof(%s)) = %s%d.vu64;", + ty, + NGEN_VALUE_PREFIX, ins.Values[0], + uint64(ins.Immediates[1]), + ty, + NGEN_VALUE_PREFIX, ins.Values[1], + ) +} + +func (c *SSAFunctionCompiler) NGen(selfID uint64, numParams uint64, numLocals uint64, numGlobals uint64) string { + builder := &strings.Builder{} + + bSprintf(builder, "uint64_t %s%d(struct VirtualMachine *vm", NGEN_FUNCTION_PREFIX, selfID) + + for i := uint64(0); i < numParams; i++ { + bSprintf(builder, ",uint64_t %s%d", NGEN_LOCAL_PREFIX, i) + } + builder.WriteString(") {\n") + + for i := uint64(0); i < numLocals; i++ { + bSprintf(builder, "uint64_t %s%d = 0;\n", NGEN_LOCAL_PREFIX, i+numParams) + } + + body := &strings.Builder{} + valueIDs := make(map[TyValueID]struct{}) + + for i, ins := range c.Code { + valueIDs[ins.Target] = struct{}{} + + bSprintf(body, "%s%d: ", NGEN_INS_LABEL_PREFIX, i) + switch ins.Op { + case "unreachable": + bSprintf(body, "vm->throw_s(vm, \"unreachable executed\");") + case "return": + if len(ins.Values) == 0 { + body.WriteString("return 0;") + } else { + bSprintf(body, "return %s%d.vu64;", NGEN_VALUE_PREFIX, ins.Values[0]) + } + case "get_local": + bSprintf(body, + "%s%d.vu64 = %s%d;", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_LOCAL_PREFIX, ins.Immediates[0], + ) + case "set_local": + bSprintf(body, + "%s%d = %s%d.vu64;", + NGEN_LOCAL_PREFIX, ins.Immediates[0], + NGEN_VALUE_PREFIX, ins.Values[0], + ) + case "get_global": + if uint64(ins.Immediates[0]) >= numGlobals { + panic("global index out of bounds") + } + bSprintf(body, + "%s%d.vu64 = globals[%d];", + NGEN_VALUE_PREFIX, ins.Target, + uint64(ins.Immediates[0]), + ) + case "set_global": + if uint64(ins.Immediates[0]) >= numGlobals { + panic("global index out of bounds") + } + bSprintf(body, + "globals[%d] = %s%d.vu64;", + uint64(ins.Immediates[0]), + NGEN_VALUE_PREFIX, ins.Values[0], + ) + case "call": + bSprintf(body, + "%s%d.vu64 = %s%d(vm", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_FUNCTION_PREFIX, ins.Immediates[0], + ) + for _, v := range ins.Values { + bSprintf(body, ",%s%d.vu64", NGEN_VALUE_PREFIX, v) + } + body.WriteString(");") + case "call_indirect": + bSprintf(body, + "%s%d.vu64 = ((uint64_t (*)(struct VirtualMachine *", + NGEN_VALUE_PREFIX, ins.Target, + ) + for range ins.Values[:len(ins.Values)-1] { + bSprintf(body, ",uint64_t") + } + bSprintf(body, + ")) %sresolve_indirect(vm, %s%d.vu32, %d)) (vm", + NGEN_ENV_API_PREFIX, + NGEN_VALUE_PREFIX, ins.Values[len(ins.Values)-1], + len(ins.Values)-1, + ) + for _, v := range ins.Values[:len(ins.Values)-1] { + bSprintf(body, ",%s%d.vu64", NGEN_VALUE_PREFIX, v) + } + body.WriteString(");") + case "jmp": + bSprintf(body, + "phi = %s%d; goto %s%d;", + NGEN_VALUE_PREFIX, ins.Values[0], + NGEN_INS_LABEL_PREFIX, ins.Immediates[0], + ) + case "jmp_if": + bSprintf(body, + "if(%s%d.vu32) { phi = %s%d; goto %s%d; }", + NGEN_VALUE_PREFIX, ins.Values[0], + NGEN_VALUE_PREFIX, ins.Values[1], + NGEN_INS_LABEL_PREFIX, ins.Immediates[0], + ) + case "jmp_either": + bSprintf(body, + "phi = %s%d; if(%s%d.vu32) { goto %s%d; } else { goto %s%d; }", + NGEN_VALUE_PREFIX, ins.Values[1], + NGEN_VALUE_PREFIX, ins.Values[0], + NGEN_INS_LABEL_PREFIX, ins.Immediates[0], + NGEN_INS_LABEL_PREFIX, ins.Immediates[1], + ) + case "jmp_table": + bSprintf(body, "phi = %s%d;\n", NGEN_VALUE_PREFIX, ins.Values[1]) + bSprintf(body, "switch(%s%d.vu32) {\n", NGEN_VALUE_PREFIX, ins.Values[0]) + for i, v := range ins.Immediates { + if i == len(ins.Immediates)-1 { + bSprintf(body, "default: ") + } else { + bSprintf(body, "case %d: ", i) + } + bSprintf(body, "goto %s%d;\n", NGEN_INS_LABEL_PREFIX, v) + } + bSprintf(body, "}") + + case "phi": + bSprintf(body, + "%s%d = phi;", + NGEN_VALUE_PREFIX, ins.Target, + ) + case "select": + bSprintf(body, + "%s%d = %s%d.vu32 ? %s%d : %s%d;", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_VALUE_PREFIX, ins.Values[2], + NGEN_VALUE_PREFIX, ins.Values[0], + NGEN_VALUE_PREFIX, ins.Values[1], + ) + case "i32.const", "f32.const": + bSprintf(body, + "%s%d.vu64 = (uint32_t) (%du);", + NGEN_VALUE_PREFIX, ins.Target, + uint32(ins.Immediates[0]), + ) + case "i32.add": + writeBinOp(body, ins, "+", "uint32_t") + case "i32.sub": + writeBinOp(body, ins, "-", "uint32_t") + case "i32.mul": + writeBinOp(body, ins, "*", "uint32_t") + case "i32.div_s": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "/", "int32_t") + case "i32.div_u": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "/", "uint32_t") + case "i32.rem_s": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "%", "int32_t") + case "i32.rem_u": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "%", "uint32_t") + case "i32.and": + writeBinOp(body, ins, "&", "uint32_t") + case "i32.or": + writeBinOp(body, ins, "|", "uint32_t") + case "i32.xor": + writeBinOp(body, ins, "^", "uint32_t") + case "i32.shl": + writeBinOp_Shift(body, ins, "<<", "uint32_t", 32) + case "i32.shr_s": + writeBinOp_Shift(body, ins, ">>", "int32_t", 32) + case "i32.shr_u": + writeBinOp_Shift(body, ins, ">>", "uint32_t", 32) + case "i32.rotl": + writeBinOp_Fcall(body, ins, "rotl32", "uint32_t", "uint64_t") + case "i32.rotr": + writeBinOp_Fcall(body, ins, "rotr32", "uint32_t", "uint64_t") + case "i32.clz": + writeUnOp_Fcall(body, ins, "clz32", "uint32_t", "uint64_t") + case "i32.ctz": + writeUnOp_Fcall(body, ins, "ctz32", "uint32_t", "uint64_t") + case "i32.popcnt": + writeUnOp_Fcall(body, ins, "popcnt32", "uint32_t", "uint64_t") + case "i32.eqz": + writeUnOp_Eqz(body, ins, "uint32_t") + case "i32.eq": + writeBinOp(body, ins, "==", "uint32_t") + case "i32.ne": + writeBinOp(body, ins, "!=", "uint32_t") + case "i32.lt_s": + writeBinOp(body, ins, "<", "int32_t") + case "i32.lt_u": + writeBinOp(body, ins, "<", "uint32_t") + case "i32.le_s": + writeBinOp(body, ins, "<=", "int32_t") + case "i32.le_u": + writeBinOp(body, ins, "<=", "uint32_t") + case "i32.gt_s": + writeBinOp(body, ins, ">", "int32_t") + case "i32.gt_u": + writeBinOp(body, ins, ">", "uint32_t") + case "i32.ge_s": + writeBinOp(body, ins, ">=", "int32_t") + case "i32.ge_u": + writeBinOp(body, ins, ">=", "uint32_t") + case "i64.const", "f64.const": + bSprintf(body, + "%s%d.vu64 = (uint64_t) (%dull);", + NGEN_VALUE_PREFIX, ins.Target, + uint64(ins.Immediates[0]), + ) + case "i64.add": + writeBinOp(body, ins, "+", "uint64_t") + case "i64.sub": + writeBinOp(body, ins, "-", "uint64_t") + case "i64.mul": + writeBinOp(body, ins, "*", "uint64_t") + case "i64.div_s": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "/", "int64_t") + case "i64.div_u": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "/", "uint64_t") + case "i64.rem_s": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "%", "int64_t") + case "i64.rem_u": + writeDivZeroRvCheck(body, ins) + writeBinOp(body, ins, "%", "uint64_t") + case "i64.and": + writeBinOp(body, ins, "&", "uint64_t") + case "i64.or": + writeBinOp(body, ins, "|", "uint64_t") + case "i64.xor": + writeBinOp(body, ins, "^", "uint64_t") + case "i64.shl": + writeBinOp_Shift(body, ins, "<<", "uint64_t", 64) + case "i64.shr_s": + writeBinOp_Shift(body, ins, ">>", "int64_t", 64) + case "i64.shr_u": + writeBinOp_Shift(body, ins, ">>", "uint64_t", 64) + case "i64.rotl": + writeBinOp_Fcall(body, ins, "rotl64", "uint64_t", "uint64_t") + case "i64.rotr": + writeBinOp_Fcall(body, ins, "rotr64", "uint64_t", "uint64_t") + case "i64.clz": + writeUnOp_Fcall(body, ins, "clz64", "uint64_t", "uint64_t") + case "i64.ctz": + writeUnOp_Fcall(body, ins, "ctz64", "uint64_t", "uint64_t") + case "i64.popcnt": + writeUnOp_Fcall(body, ins, "popcnt64", "uint64_t", "uint64_t") + case "i64.eqz": + writeUnOp_Eqz(body, ins, "uint64_t") + case "i64.eq": + writeBinOp(body, ins, "==", "uint64_t") + case "i64.ne": + writeBinOp(body, ins, "!=", "uint64_t") + case "i64.lt_s": + writeBinOp(body, ins, "<", "int64_t") + case "i64.lt_u": + writeBinOp(body, ins, "<", "uint64_t") + case "i64.le_s": + writeBinOp(body, ins, "<=", "int64_t") + case "i64.le_u": + writeBinOp(body, ins, "<=", "uint64_t") + case "i64.gt_s": + writeBinOp(body, ins, ">", "int64_t") + case "i64.gt_u": + writeBinOp(body, ins, ">", "uint64_t") + case "i64.ge_s": + writeBinOp(body, ins, ">=", "int64_t") + case "i64.ge_u": + writeBinOp(body, ins, ">=", "uint64_t") + case "f32.add": + writeBinOp(body, ins, "+", "float") + case "f32.sub": + writeBinOp(body, ins, "-", "float") + case "f32.mul": + writeBinOp(body, ins, "*", "float") + case "f32.div": + writeBinOp(body, ins, "/", "float") + case "f32.sqrt": + writeUnOp_Fcall(body, ins, "fsqrt32", "float", "float") + case "f32.min": + writeBinOp_Fcall(body, ins, "fmin32", "float", "float") + case "f32.max": + writeBinOp_Fcall(body, ins, "fmax32", "float", "float") + case "f32.ceil": + writeUnOp_Fcall(body, ins, "fceil32", "float", "float") + case "f32.floor": + writeUnOp_Fcall(body, ins, "ffloor32", "float", "float") + case "f32.trunc": + writeUnOp_Fcall(body, ins, "ftrunc32", "float", "float") + case "f32.nearest": + writeUnOp_Fcall(body, ins, "fnearest32", "float", "float") + case "f32.abs": + writeUnOp_Fcall(body, ins, "fabs32", "float", "float") + case "f32.neg": + writeUnOp_Fcall(body, ins, "fneg32", "float", "float") + case "f32.copysign": + writeBinOp_Fcall(body, ins, "fcopysign32", "float", "float") + case "f32.eq": + writeBinOp2(body, ins, "==", "float", "uint64_t") + case "f32.ne": + writeBinOp2(body, ins, "!=", "float", "uint64_t") + case "f32.lt": + writeBinOp2(body, ins, "<", "float", "uint64_t") + case "f32.le": + writeBinOp2(body, ins, "<=", "float", "uint64_t") + case "f32.gt": + writeBinOp2(body, ins, ">", "float", "uint64_t") + case "f32.ge": + writeBinOp2(body, ins, ">=", "float", "uint64_t") + + case "f64.add": + writeBinOp(body, ins, "+", "double") + case "f64.sub": + writeBinOp(body, ins, "-", "double") + case "f64.mul": + writeBinOp(body, ins, "*", "double") + case "f64.div": + writeBinOp(body, ins, "/", "double") + case "f64.sqrt": + writeUnOp_Fcall(body, ins, "fsqrt64", "double", "double") + case "f64.min": + writeBinOp_Fcall(body, ins, "fmin64", "double", "double") + case "f64.max": + writeBinOp_Fcall(body, ins, "fmax64", "double", "double") + case "f64.ceil": + writeUnOp_Fcall(body, ins, "fceil64", "double", "double") + case "f64.floor": + writeUnOp_Fcall(body, ins, "ffloor64", "double", "double") + case "f64.trunc": + writeUnOp_Fcall(body, ins, "ftrunc64", "double", "double") + case "f64.nearest": + writeUnOp_Fcall(body, ins, "fnearest64", "double", "double") + case "f64.abs": + writeUnOp_Fcall(body, ins, "fabs64", "double", "double") + case "f64.neg": + writeUnOp_Fcall(body, ins, "fneg64", "double", "double") + case "f64.copysign": + writeBinOp_Fcall(body, ins, "fcopysign64", "double", "double") + case "f64.eq": + writeBinOp2(body, ins, "==", "double", "uint64_t") + case "f64.ne": + writeBinOp2(body, ins, "!=", "double", "uint64_t") + case "f64.lt": + writeBinOp2(body, ins, "<", "double", "uint64_t") + case "f64.le": + writeBinOp2(body, ins, "<=", "double", "uint64_t") + case "f64.gt": + writeBinOp2(body, ins, ">", "double", "uint64_t") + case "f64.ge": + writeBinOp2(body, ins, ">=", "double", "uint64_t") + + case "i64.extend_u/i32": + writeUnOp_Fcall(body, ins, "", "uint32_t", "uint64_t") + case "i64.extend_s/i32": + writeUnOp_Fcall(body, ins, "", "int32_t", "int64_t") + + case "i32.wrap/i64": + writeUnOp_Fcall(body, ins, "", "uint32_t", "uint64_t") + + // TODO: These floating point operations need to be double-checked for correctness. + + case "i32.trunc_s/f32", "i64.trunc_s/f32", "i32.trunc_u/f32", "i64.trunc_u/f32": + writeUnOp_Fcall(body, ins, "ftrunc32", "float", "int64_t") + + case "i32.trunc_s/f64", "i64.trunc_s/f64", "i32.trunc_u/f64", "i64.trunc_u/f64": + writeUnOp_Fcall(body, ins, "ftrunc64", "double", "int64_t") + + case "f32.demote/f64": + writeUnOp_Fcall(body, ins, "", "double", "float") + + case "f64.promote/f32": + writeUnOp_Fcall(body, ins, "", "float", "double") + + case "f32.convert_s/i32": + writeUnOp_Fcall(body, ins, "", "int32_t", "float") + + case "f32.convert_s/i64": + writeUnOp_Fcall(body, ins, "", "int64_t", "float") + + case "f32.convert_u/i32": + writeUnOp_Fcall(body, ins, "", "uint32_t", "float") + + case "f32.convert_u/i64": + writeUnOp_Fcall(body, ins, "", "uint64_t", "float") + + case "f64.convert_s/i32": + writeUnOp_Fcall(body, ins, "", "int32_t", "double") + + case "f64.convert_s/i64": + writeUnOp_Fcall(body, ins, "", "int64_t", "double") + + case "f64.convert_u/i32": + writeUnOp_Fcall(body, ins, "", "uint32_t", "double") + + case "f64.convert_u/i64": + writeUnOp_Fcall(body, ins, "", "uint64_t", "double") + + case "i32.reinterpret/f32", "i64.reinterpret/f64", "f32.reinterpret/i32", "f64.reinterpret/i64": + + case "i32.load", "f32.load", "i64.load32_u": + writeMemLoad(body, ins, "uint32_t") + + case "i32.load8_s", "i64.load8_s": + writeMemLoad(body, ins, "int8_t") + + case "i32.load8_u", "i64.load8_u": + writeMemLoad(body, ins, "uint8_t") + + case "i32.load16_s", "i64.load16_s": + writeMemLoad(body, ins, "int16_t") + + case "i32.load16_u", "i64.load16_u": + writeMemLoad(body, ins, "uint16_t") + + case "i64.load32_s": + writeMemLoad(body, ins, "int32_t") + + case "i64.load", "f64.load": + writeMemLoad(body, ins, "uint64_t") + + case "i32.store", "f32.store", "i64.store32": + writeMemStore(body, ins, "uint32_t") + + case "i32.store8", "i64.store8": + writeMemStore(body, ins, "uint8_t") + + case "i32.store16", "i64.store16": + writeMemStore(body, ins, "uint16_t") + + case "i64.store", "f64.store": + writeMemStore(body, ins, "uint64_t") + + case "current_memory": + bSprintf(body, + "%s%d.vu64 = vm->mem_size / 65536;", + NGEN_VALUE_PREFIX, ins.Target, + ) + + case "grow_memory": + bSprintf(body, + "%s%d.vu64 = vm->mem_size / 65536; vm->grow_memory(vm, %s%d.vu32 * 65536);", + NGEN_VALUE_PREFIX, ins.Target, + NGEN_VALUE_PREFIX, ins.Values[0], + ) + + case "add_gas": + // TODO: Implement + + case "fp_disabled_error": + bSprintf(body, "vm->throw_s(vm, \"floating point disabled\");") + + default: + panic(ins.Op) + } + body.WriteByte('\n') + } + + body.WriteString("\nreturn 0;\n") + + bSprintf(builder, "union Value phi") + + for id, _ := range valueIDs { + bSprintf(builder, ",%s%d", NGEN_VALUE_PREFIX, id) + } + bSprintf(builder, ";\n") + + builder.WriteString(body.String()) + builder.WriteString("}\n") + + return builder.String() +} diff --git a/vendor/github.com/perlin-network/life/compiler/opcodes/gen_rs.py b/vendor/github.com/perlin-network/life/compiler/opcodes/gen_rs.py index 7292edd..07c3611 100644 --- a/vendor/github.com/perlin-network/life/compiler/opcodes/gen_rs.py +++ b/vendor/github.com/perlin-network/life/compiler/opcodes/gen_rs.py @@ -1,12 +1,14 @@ with open("opcodes.go") as f: data = f.read() lines = data.split("const (")[1].split(")")[0].strip().split("\n") + id = 0 out = "#[repr(u8)]\n#[derive(Copy, Clone, Eq, PartialEq)]\npub enum Opcode {\n" for i, line in enumerate(lines): line = line.strip().split(" ")[0] if len(line) > 0: - out += " {0} = {1},\n".format(line, i) + out += " {0} = {1},\n".format(line, id) + id += 1 out += "}\n" with open("opcodes.rs", "w") as outFile: outFile.write(out) diff --git a/vendor/github.com/perlin-network/life/compiler/opcodes/opcodes.rs b/vendor/github.com/perlin-network/life/compiler/opcodes/opcodes.rs index 185f71b..7f818cb 100644 --- a/vendor/github.com/perlin-network/life/compiler/opcodes/opcodes.rs +++ b/vendor/github.com/perlin-network/life/compiler/opcodes/opcodes.rs @@ -34,133 +34,133 @@ pub enum Opcode { I32GtU = 30, I32GeS = 31, I32GeU = 32, - I64Const = 34, - I64Add = 35, - I64Sub = 36, - I64Mul = 37, - I64DivS = 38, - I64DivU = 39, - I64RemS = 40, - I64RemU = 41, - I64Rotl = 42, - I64Rotr = 43, - I64Clz = 44, - I64Ctz = 45, - I64PopCnt = 46, - I64EqZ = 47, - I64And = 48, - I64Or = 49, - I64Xor = 50, - I64Shl = 51, - I64ShrS = 52, - I64ShrU = 53, - I64Eq = 54, - I64Ne = 55, - I64LtS = 56, - I64LtU = 57, - I64LeS = 58, - I64LeU = 59, - I64GtS = 60, - I64GtU = 61, - I64GeS = 62, - I64GeU = 63, - F32Add = 65, - F32Sub = 66, - F32Mul = 67, - F32Div = 68, - F32Sqrt = 69, - F32Min = 70, - F32Max = 71, - F32Ceil = 72, - F32Floor = 73, - F32Trunc = 74, - F32Nearest = 75, - F32Abs = 76, - F32Neg = 77, - F32CopySign = 78, - F32Eq = 79, - F32Ne = 80, - F32Lt = 81, - F32Le = 82, - F32Gt = 83, - F32Ge = 84, - F64Add = 86, - F64Sub = 87, - F64Mul = 88, - F64Div = 89, - F64Sqrt = 90, - F64Min = 91, - F64Max = 92, - F64Ceil = 93, - F64Floor = 94, - F64Trunc = 95, - F64Nearest = 96, - F64Abs = 97, - F64Neg = 98, - F64CopySign = 99, - F64Eq = 100, - F64Ne = 101, - F64Lt = 102, - F64Le = 103, - F64Gt = 104, - F64Ge = 105, - I32WrapI64 = 107, - I32TruncUF32 = 108, - I32TruncUF64 = 109, - I32TruncSF32 = 110, - I32TruncSF64 = 111, - I64TruncUF32 = 112, - I64TruncUF64 = 113, - I64TruncSF32 = 114, - I64TruncSF64 = 115, - I64ExtendUI32 = 116, - I64ExtendSI32 = 117, - F32DemoteF64 = 119, - F64PromoteF32 = 120, - F32ConvertSI32 = 121, - F32ConvertSI64 = 122, - F32ConvertUI32 = 123, - F32ConvertUI64 = 124, - F64ConvertSI32 = 125, - F64ConvertSI64 = 126, - F64ConvertUI32 = 127, - F64ConvertUI64 = 128, - I32Load = 130, - I64Load = 131, - I32Store = 133, - I64Store = 134, - I32Load8S = 136, - I32Load16S = 137, - I64Load8S = 138, - I64Load16S = 139, - I64Load32S = 140, - I32Load8U = 142, - I32Load16U = 143, - I64Load8U = 144, - I64Load16U = 145, - I64Load32U = 146, - I32Store8 = 148, - I32Store16 = 149, - I64Store8 = 150, - I64Store16 = 151, - I64Store32 = 152, - Jmp = 154, - JmpIf = 155, - JmpEither = 156, - JmpTable = 157, - ReturnValue = 158, - ReturnVoid = 159, - GetLocal = 161, - SetLocal = 162, - GetGlobal = 164, - SetGlobal = 165, - Call = 167, - CallIndirect = 168, - InvokeImport = 169, - CurrentMemory = 171, - GrowMemory = 172, - Phi = 174, - AddGas = 176, - FPDisabledError = 178, - Unknown = 180, + I64Const = 33, + I64Add = 34, + I64Sub = 35, + I64Mul = 36, + I64DivS = 37, + I64DivU = 38, + I64RemS = 39, + I64RemU = 40, + I64Rotl = 41, + I64Rotr = 42, + I64Clz = 43, + I64Ctz = 44, + I64PopCnt = 45, + I64EqZ = 46, + I64And = 47, + I64Or = 48, + I64Xor = 49, + I64Shl = 50, + I64ShrS = 51, + I64ShrU = 52, + I64Eq = 53, + I64Ne = 54, + I64LtS = 55, + I64LtU = 56, + I64LeS = 57, + I64LeU = 58, + I64GtS = 59, + I64GtU = 60, + I64GeS = 61, + I64GeU = 62, + F32Add = 63, + F32Sub = 64, + F32Mul = 65, + F32Div = 66, + F32Sqrt = 67, + F32Min = 68, + F32Max = 69, + F32Ceil = 70, + F32Floor = 71, + F32Trunc = 72, + F32Nearest = 73, + F32Abs = 74, + F32Neg = 75, + F32CopySign = 76, + F32Eq = 77, + F32Ne = 78, + F32Lt = 79, + F32Le = 80, + F32Gt = 81, + F32Ge = 82, + F64Add = 83, + F64Sub = 84, + F64Mul = 85, + F64Div = 86, + F64Sqrt = 87, + F64Min = 88, + F64Max = 89, + F64Ceil = 90, + F64Floor = 91, + F64Trunc = 92, + F64Nearest = 93, + F64Abs = 94, + F64Neg = 95, + F64CopySign = 96, + F64Eq = 97, + F64Ne = 98, + F64Lt = 99, + F64Le = 100, + F64Gt = 101, + F64Ge = 102, + I32WrapI64 = 103, + I32TruncUF32 = 104, + I32TruncUF64 = 105, + I32TruncSF32 = 106, + I32TruncSF64 = 107, + I64TruncUF32 = 108, + I64TruncUF64 = 109, + I64TruncSF32 = 110, + I64TruncSF64 = 111, + I64ExtendUI32 = 112, + I64ExtendSI32 = 113, + F32DemoteF64 = 114, + F64PromoteF32 = 115, + F32ConvertSI32 = 116, + F32ConvertSI64 = 117, + F32ConvertUI32 = 118, + F32ConvertUI64 = 119, + F64ConvertSI32 = 120, + F64ConvertSI64 = 121, + F64ConvertUI32 = 122, + F64ConvertUI64 = 123, + I32Load = 124, + I64Load = 125, + I32Store = 126, + I64Store = 127, + I32Load8S = 128, + I32Load16S = 129, + I64Load8S = 130, + I64Load16S = 131, + I64Load32S = 132, + I32Load8U = 133, + I32Load16U = 134, + I64Load8U = 135, + I64Load16U = 136, + I64Load32U = 137, + I32Store8 = 138, + I32Store16 = 139, + I64Store8 = 140, + I64Store16 = 141, + I64Store32 = 142, + Jmp = 143, + JmpIf = 144, + JmpEither = 145, + JmpTable = 146, + ReturnValue = 147, + ReturnVoid = 148, + GetLocal = 149, + SetLocal = 150, + GetGlobal = 151, + SetGlobal = 152, + Call = 153, + CallIndirect = 154, + InvokeImport = 155, + CurrentMemory = 156, + GrowMemory = 157, + Phi = 158, + AddGas = 159, + FPDisabledError = 160, + Unknown = 161, } diff --git a/vendor/github.com/perlin-network/life/compiler/ssa.go b/vendor/github.com/perlin-network/life/compiler/ssa.go index b5d80e2..948df20 100644 --- a/vendor/github.com/perlin-network/life/compiler/ssa.go +++ b/vendor/github.com/perlin-network/life/compiler/ssa.go @@ -134,7 +134,7 @@ func (c *SSAFunctionCompiler) FilterFloatingPoint() { if strings.Contains(ins.Op, ".reinterpret/") || strings.HasSuffix(ins.Op, ".const") { continue // whitelist } - c.Code[i] = buildInstr(0, "fp_disabled_error", nil, nil) + c.Code[i] = buildInstr(ins.Target, "fp_disabled_error", nil, nil) } } } diff --git a/vendor/github.com/perlin-network/life/exec/helpers.go b/vendor/github.com/perlin-network/life/exec/helpers.go index 94f4e4f..9998862 100644 --- a/vendor/github.com/perlin-network/life/exec/helpers.go +++ b/vendor/github.com/perlin-network/life/exec/helpers.go @@ -3,6 +3,8 @@ package exec import ( "errors" + "fmt" + "github.com/perlin-network/life/compiler" "github.com/perlin-network/life/utils" ) @@ -47,8 +49,36 @@ func (vm *VirtualMachine) RunWithGasLimit(entryID, limit int, params ...int64) ( // Run runs a WebAssembly modules function denoted by its ID with a specified set // of parameters. // Panics on logical errors. -func (vm *VirtualMachine) Run(entryID int, params ...int64) (int64, error) { - vm.Ignite(entryID, params...) +func (vm *VirtualMachine) Run(entryID int, params ...int64) (retVal int64, retErr error) { + vm.Ignite(entryID, params...) // call Ignite() to perform necessary checks even if we are using the AOT mode. + + if vm.AOTService != nil { + recoveryFunc := func() { + if err := recover(); err != nil { + if err, ok := err.(error); ok { + retErr = err + } else { + panic(err) + } + } else { + vm.CurrentFrame = -1 + } + } + targetName := fmt.Sprintf("%s%d", compiler.NGEN_FUNCTION_PREFIX, entryID) + switch len(params) { + case 0: + defer recoveryFunc() + return int64(vm.AOTService.UnsafeInvokeFunction_0(vm, targetName)), nil + case 1: + defer recoveryFunc() + return int64(vm.AOTService.UnsafeInvokeFunction_1(vm, targetName, uint64(params[0]))), nil + case 2: + defer recoveryFunc() + return int64(vm.AOTService.UnsafeInvokeFunction_2(vm, targetName, uint64(params[0]), uint64(params[1]))), nil + default: + } + } + for !vm.Exited { vm.Execute() if vm.Delegate != nil { diff --git a/vendor/github.com/perlin-network/life/exec/vm.go b/vendor/github.com/perlin-network/life/exec/vm.go index 866199b..2b52392 100644 --- a/vendor/github.com/perlin-network/life/exec/vm.go +++ b/vendor/github.com/perlin-network/life/exec/vm.go @@ -5,15 +5,17 @@ import ( "fmt" "math" "math/bits" + "runtime/debug" "github.com/perlin-network/life/compiler" "github.com/perlin-network/life/compiler/opcodes" "github.com/perlin-network/life/utils" + "strings" + "github.com/go-interpreter/wagon/wasm" ) -// FunctionImport represents the function import type. If len(sig.ReturnTypes) == 0, the return value will be ignored. type FunctionImport func(vm *VirtualMachine) int64 const ( @@ -30,12 +32,29 @@ const ( // LE is a simple alias to `binary.LittleEndian`. var LE = binary.LittleEndian +type FunctionImportInfo struct { + ModuleName string + FieldName string + F FunctionImport +} + +type NCompileConfig struct { + AliasDef bool + DisableMemBoundCheck bool +} + +type AOTService interface { + UnsafeInvokeFunction_0(vm *VirtualMachine, name string) uint64 + UnsafeInvokeFunction_1(vm *VirtualMachine, name string, p0 uint64) uint64 + UnsafeInvokeFunction_2(vm *VirtualMachine, name string, p0, p1 uint64) uint64 +} + // VirtualMachine is a WebAssembly execution environment. type VirtualMachine struct { Config VMConfig Module *compiler.Module FunctionCode []compiler.InterpreterCode - FunctionImports []FunctionImport + FunctionImports []FunctionImportInfo CallStack []Frame CurrentFrame int Table []uint32 @@ -50,6 +69,10 @@ type VirtualMachine struct { ReturnValue int64 Gas uint64 GasLimitExceeded bool + GasPolicy compiler.GasPolicy + ImportResolver ImportResolver + AOTService AOTService + StackTrace string } // VMConfig denotes a set of options passed to a single VirtualMachine insta.ce @@ -113,13 +136,17 @@ func NewVirtualMachine( table := make([]uint32, 0) globals := make([]int64, 0) - funcImports := make([]FunctionImport, 0) + funcImports := make([]FunctionImportInfo, 0) if m.Base.Import != nil && impResolver != nil { for _, imp := range m.Base.Import.Entries { switch imp.Type.Kind() { case wasm.ExternalFunction: - funcImports = append(funcImports, impResolver.ResolveFunc(imp.ModuleName, imp.FieldName)) + funcImports = append(funcImports, FunctionImportInfo{ + ModuleName: imp.ModuleName, + FieldName: imp.FieldName, + F: nil, // deferred + }) case wasm.ExternalGlobal: globals = append(globals, impResolver.ResolveGlobal(imp.ModuleName, imp.FieldName)) case wasm.ExternalMemory: @@ -216,9 +243,147 @@ func NewVirtualMachine( Globals: globals, Memory: memory, Exited: true, + GasPolicy: gasPolicy, + ImportResolver: impResolver, }, nil } +func (vm *VirtualMachine) SetAOTService(s AOTService) { + vm.AOTService = s +} + +func bSprintf(builder *strings.Builder, format string, args ...interface{}) { + builder.WriteString(fmt.Sprintf(format, args...)) +} + +func escapeName(name string) string { + ret := "" + + for _, ch := range []byte(name) { + if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' { + ret += string(ch) + } else { + ret += fmt.Sprintf("\\x%02x", ch) + } + } + + return ret +} + +func filterName(name string) string { + ret := "" + + for _, ch := range []byte(name) { + if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' { + ret += string(ch) + } + } + + return ret +} + +func (vm *VirtualMachine) GenerateNEnv(config NCompileConfig) string { + builder := &strings.Builder{} + + bSprintf(builder, "#include \n\n") + + if config.DisableMemBoundCheck { + builder.WriteString("#define POLYMERASE_NO_MEM_BOUND_CHECK\n") + } + + builder.WriteString(compiler.NGEN_HEADER) + if !vm.Config.DisableFloatingPoint { + builder.WriteString(compiler.NGEN_FP_HEADER) + } + + bSprintf(builder, "static uint64_t globals[] = {") + for _, v := range vm.Globals { + bSprintf(builder, "%dull,", uint64(v)) + } + bSprintf(builder, "};\n") + + for i, code := range vm.FunctionCode { + bSprintf(builder, "uint64_t %s%d(struct VirtualMachine *", compiler.NGEN_FUNCTION_PREFIX, i) + for j := 0; j < code.NumParams; j++ { + bSprintf(builder, ",uint64_t") + } + bSprintf(builder, ");\n") + } + + // call_indirect dispatcher. + bSprintf(builder, "struct TableEntry { uint64_t num_params; void *func; };\n") + bSprintf(builder, "static const uint64_t num_table_entries = %d;\n", len(vm.Table)) + bSprintf(builder, "static struct TableEntry table[] = {\n") + for _, entry := range vm.Table { + if entry == math.MaxUint32 { + bSprintf(builder, "{ .num_params = 0, .func = 0 },\n") + } else { + functionID := int(entry) + code := vm.FunctionCode[functionID] + + bSprintf(builder, "{ .num_params = %d, .func = %s%d },\n", code.NumParams, compiler.NGEN_FUNCTION_PREFIX, functionID) + } + } + bSprintf(builder, "};\n") + bSprintf(builder, "static void * __attribute__((always_inline)) %sresolve_indirect(struct VirtualMachine *vm, uint64_t entry_id, uint64_t num_params) {\n", compiler.NGEN_ENV_API_PREFIX) + bSprintf(builder, "if(entry_id >= num_table_entries) { vm->throw_s(vm, \"%s\"); }\n", "table entry out of bounds") + bSprintf(builder, "if(table[entry_id].func == 0) { vm->throw_s(vm, \"%s\"); }\n", "table entry is null") + bSprintf(builder, "if(table[entry_id].num_params != num_params) { vm->throw_s(vm, \"%s\"); }\n", "argument count mismatch") + bSprintf(builder, "return table[entry_id].func;\n") + bSprintf(builder, "}\n") + + bSprintf(builder, "struct ImportEntry { const char *module_name; const char *field_name; ExternalFunction f; };\n") + bSprintf(builder, "static const uint64_t num_import_entries = %d;\n", len(vm.FunctionImports)) + bSprintf(builder, "static struct ImportEntry imports[] = {\n") + for _, imp := range vm.FunctionImports { + bSprintf(builder, "{ .module_name = \"%s\", .field_name = \"%s\", .f = 0 },\n", escapeName(imp.ModuleName), escapeName(imp.FieldName)) + } + bSprintf(builder, "};\n") + bSprintf(builder, + "static uint64_t __attribute__((always_inline)) %sinvoke_import(struct VirtualMachine *vm, uint64_t import_id, uint64_t num_params, uint64_t *params) {\n", + compiler.NGEN_ENV_API_PREFIX, + ) + + bSprintf(builder, "if(import_id >= num_import_entries) { vm->throw_s(vm, \"%s\"); }\n", "import entry out of bounds") + bSprintf(builder, "if(imports[import_id].f == 0) { imports[import_id].f = vm->resolve_import(vm, imports[import_id].module_name, imports[import_id].field_name); }\n") + bSprintf(builder, "if(imports[import_id].f == 0) { vm->throw_s(vm, \"%s\"); }\n", "cannot resolve import") + bSprintf(builder, "return imports[import_id].f(vm, import_id, num_params, params);\n") + bSprintf(builder, "}\n") + + return builder.String() +} + +func (vm *VirtualMachine) NBuildAliasDef() string { + builder := &strings.Builder{} + + builder.WriteString("// Aliases for exported functions\n") + + if vm.Module.Base.Export != nil { + for name, exp := range vm.Module.Base.Export.Entries { + if exp.Kind == wasm.ExternalFunction { + bSprintf(builder, "#define %sexport_%s %s%d\n", compiler.NGEN_FUNCTION_PREFIX, filterName(name), compiler.NGEN_FUNCTION_PREFIX, exp.Index) + } + } + } + + return builder.String() +} + +func (vm *VirtualMachine) NCompile(config NCompileConfig) string { + body, err := vm.Module.CompileWithNGen(vm.GasPolicy, uint64(len(vm.Globals))) + if err != nil { + panic(err) + } + + out := vm.GenerateNEnv(config) + "\n" + body + if config.AliasDef { + out += "\n" + out += vm.NBuildAliasDef() + } + + return out +} + // Init initializes a frame. Must be called on `call` and `call_indirect`. func (f *Frame) Init(vm *VirtualMachine, functionID int, code compiler.InterpreterCode) { numValueSlots := code.NumRegs + code.NumParams + code.NumLocals @@ -364,6 +529,7 @@ func (vm *VirtualMachine) Execute() { if err := recover(); err != nil { vm.Exited = true vm.ExitError = err + vm.StackTrace = string(debug.Stack()) } }() @@ -844,69 +1010,141 @@ func (vm *VirtualMachine) Execute() { a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(a + b)) + + if c := a + b; c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } + case opcodes.F32Sub: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(a - b)) + + if c := a - b; c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Mul: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(a * b)) + + if c := a * b; c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Div: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(a / b)) + + if c := a / b; c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Sqrt: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Sqrt(float64(val))))) + + if c := float32(math.Sqrt(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Min: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Min(float64(a), float64(b))))) + + if c := float32(math.Min(float64(a), float64(b))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Max: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Max(float64(a), float64(b))))) + + if c := float32(math.Max(float64(a), float64(b))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Ceil: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Ceil(float64(val))))) + + if c := float32(math.Ceil(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Floor: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Floor(float64(val))))) + + if c := float32(math.Floor(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Trunc: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Trunc(float64(val))))) + + if c := float32(math.Trunc(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Nearest: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.RoundToEven(float64(val))))) + + if c := float32(math.RoundToEven(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Abs: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Abs(float64(val))))) + + if c := float32(math.Abs(float64(val))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Neg: val := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float32bits(-val)) + + if c := float32(-val); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32CopySign: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float32bits(float32(math.Copysign(float64(a), float64(b))))) + + if c := float32(math.Copysign(float64(a), float64(b))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(math.Float32bits(c)) + } case opcodes.F32Eq: a := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 + if a == b { frame.Regs[valueID] = 1 } else { @@ -961,65 +1199,135 @@ func (vm *VirtualMachine) Execute() { a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(a + b)) + + if c := a + b; c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Sub: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(a - b)) + + if c := a - b; c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Mul: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(a * b)) + + if c := a * b; c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Div: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(a / b)) + + if c := a / b; c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Sqrt: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.Sqrt(val))) + + if c := math.Sqrt(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Min: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(math.Min(a, b))) + + if c := math.Min(a, b); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Max: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(math.Max(a, b))) + + if c := math.Max(a, b); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Ceil: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.Ceil(val))) + + if c := math.Ceil(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Floor: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.Floor(val))) + + if c := math.Floor(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Trunc: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.Trunc(val))) + + if c := math.Trunc(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Nearest: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.RoundToEven(val))) + + if c := math.RoundToEven(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Abs: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(math.Abs(val))) + + if c := math.Abs(val); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Neg: val := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(-val)) + + if c := -val; c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64CopySign: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) frame.IP += 8 - frame.Regs[valueID] = int64(math.Float64bits(math.Copysign(a, b))) + + if c := math.Copysign(a, b); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F64Eq: a := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) b := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+4:frame.IP+8]))])) @@ -1083,23 +1391,39 @@ func (vm *VirtualMachine) Execute() { case opcodes.I32TruncSF32, opcodes.I32TruncUF32: v := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(int32(math.Trunc(float64(v)))) + if c := float32(math.Trunc(float64(v))); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(int32(c)) + } case opcodes.I32TruncSF64, opcodes.I32TruncUF64: v := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(int32(math.Trunc(v))) + if c := math.Trunc(v); c != c { + frame.Regs[valueID] = int64(0x7FC00000) + } else { + frame.Regs[valueID] = int64(int32(c)) + } case opcodes.I64TruncSF32, opcodes.I64TruncUF32: v := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Trunc(float64(v))) + if c := math.Trunc(float64(v)); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(c) + } case opcodes.I64TruncSF64, opcodes.I64TruncUF64: v := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Trunc(v)) + if c := math.Trunc(v); c != c { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(c) + } case opcodes.F32DemoteF64: v := math.Float64frombits(uint64(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 @@ -1108,8 +1432,12 @@ func (vm *VirtualMachine) Execute() { case opcodes.F64PromoteF32: v := math.Float32frombits(uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))])) frame.IP += 4 - frame.Regs[valueID] = int64(math.Float64bits(float64(v))) + if c := float64(v); c == math.Float64frombits(0x7FF8000000000000) { + frame.Regs[valueID] = int64(0x7FF8000000000001) + } else { + frame.Regs[valueID] = int64(math.Float64bits(c)) + } case opcodes.F32ConvertSI32: v := int32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP:frame.IP+4]))]) frame.IP += 4 @@ -1225,6 +1553,7 @@ func (vm *VirtualMachine) Execute() { frame.Regs[valueID] = int64(uint16(LE.Uint16(vm.Memory[effective : effective+2]))) case opcodes.I32Store, opcodes.I64Store32: LE.Uint32(frame.Code[frame.IP : frame.IP+4]) + offset := LE.Uint32(frame.Code[frame.IP+4 : frame.IP+8]) base := uint32(frame.Regs[int(LE.Uint32(frame.Code[frame.IP+8:frame.IP+12]))]) @@ -1413,7 +1742,17 @@ func (vm *VirtualMachine) Execute() { importID := int(LE.Uint32(frame.Code[frame.IP : frame.IP+4])) frame.IP += 4 vm.Delegate = func() { - frame.Regs[valueID] = vm.FunctionImports[importID](vm) + defer func() { + if err := recover(); err != nil { + vm.Exited = true + vm.ExitError = err + } + }() + imp := vm.FunctionImports[importID] + if imp.F == nil { + imp.F = vm.ImportResolver.ResolveFunc(imp.ModuleName, imp.FieldName) + } + frame.Regs[valueID] = imp.F(vm) } return diff --git a/vendor/github.com/perlin-network/life/utils/catch.go b/vendor/github.com/perlin-network/life/utils/catch.go index c36aae0..494d032 100644 --- a/vendor/github.com/perlin-network/life/utils/catch.go +++ b/vendor/github.com/perlin-network/life/utils/catch.go @@ -2,12 +2,13 @@ package utils import ( "fmt" + "runtime/debug" ) // CatchPanic catches any panic and writes the error to out. func CatchPanic(out *error) { if err := recover(); err != nil { - *out = UnifyError(err) + *out = fmt.Errorf("Error: %s\n---GO TRACEBACK---\n%s", UnifyError(err), string(debug.Stack())) } } diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml index 588ceca..d4b9266 100644 --- a/vendor/github.com/pkg/errors/.travis.yml +++ b/vendor/github.com/pkg/errors/.travis.yml @@ -1,10 +1,14 @@ language: go go_import_path: github.com/pkg/errors go: - - 1.4.3 - - 1.5.4 - - 1.6.2 - - 1.7.1 + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x - tip script: diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md index 273db3c..6483ba2 100644 --- a/vendor/github.com/pkg/errors/README.md +++ b/vendor/github.com/pkg/errors/README.md @@ -1,4 +1,4 @@ -# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) Package errors provides simple error handling primitives. @@ -47,6 +47,6 @@ We welcome pull requests, bug fixes and issue reports. With that said, the bar f Before proposing a change, please discuss your change by raising an issue. -## Licence +## License BSD-2-Clause diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 842ee80..7421f32 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -6,7 +6,7 @@ // return err // } // -// which applied recursively up the call stack results in error reports +// which when applied recursively up the call stack results in error reports // without context or debugging information. The errors package allows // programmers to add context to the failure path in their code in a way // that does not destroy the original value of the error. @@ -15,16 +15,17 @@ // // The errors.Wrap function returns a new error that adds context to the // original error by recording a stack trace at the point Wrap is called, -// and the supplied message. For example +// together with the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { // return errors.Wrap(err, "read failed") // } // -// If additional control is required the errors.WithStack and errors.WithMessage -// functions destructure errors.Wrap into its component operations of annotating -// an error with a stack trace and an a message, respectively. +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. // // Retrieving the cause of an error // @@ -38,7 +39,7 @@ // } // // can be inspected by errors.Cause. errors.Cause will recursively retrieve -// the topmost error which does not implement causer, which is assumed to be +// the topmost error that does not implement causer, which is assumed to be // the original cause. For example: // // switch err := errors.Cause(err).(type) { @@ -48,16 +49,16 @@ // // unknown error // } // -// causer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. // // Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can -// be formatted by the fmt package. The following verbs are supported +// be formatted by the fmt package. The following verbs are supported: // // %s print the error. If the error has a Cause it will be -// printed recursively +// printed recursively. // %v see %s // %+v extended format. Each Frame of the error's StackTrace will // be printed in detail. @@ -65,13 +66,13 @@ // Retrieving the stack trace of an error or wrapper // // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are -// invoked. This information can be retrieved with the following interface. +// invoked. This information can be retrieved with the following interface: // // type stackTracer interface { // StackTrace() errors.StackTrace // } // -// Where errors.StackTrace is defined as +// The returned errors.StackTrace type is defined as // // type StackTrace []Frame // @@ -85,8 +86,8 @@ // } // } // -// stackTracer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. // // See the documentation for Frame.Format for more details. package errors @@ -192,7 +193,7 @@ func Wrap(err error, message string) error { } // Wrapf returns an error annotating err with a stack trace -// at the point Wrapf is call, and the format specifier. +// at the point Wrapf is called, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { @@ -220,6 +221,18 @@ func WithMessage(err error, message string) error { } } +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + type withMessage struct { cause error msg string diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 6b1f289..2874a04 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -46,7 +46,8 @@ func (f Frame) line() int { // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+s path of source file relative to the compile time GOPATH +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) // %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { switch verb { @@ -79,6 +80,14 @@ func (f Frame) Format(s fmt.State, verb rune) { // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -136,43 +145,3 @@ func funcname(name string) string { i = strings.Index(name, ".") return name[i+1:] } - -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file -} diff --git a/vendor/github.com/spaolacci/murmur3/.travis.yml b/vendor/github.com/spaolacci/murmur3/.travis.yml deleted file mode 100644 index 9bfca9c..0000000 --- a/vendor/github.com/spaolacci/murmur3/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go - -go: - - 1.x - - master - -script: go test diff --git a/vendor/github.com/ugorji/go/codec/decode.go b/vendor/github.com/ugorji/go/codec/decode.go index 4caa259..b2bb0e8 100644 --- a/vendor/github.com/ugorji/go/codec/decode.go +++ b/vendor/github.com/ugorji/go/codec/decode.go @@ -553,21 +553,33 @@ type bufioDecReader struct { // err error - _ [2]uint64 // padding + // Extensions can call Decode() within a current Decode() call. + // We need to know when the top level Decode() call returns, + // so we can decide whether to Release() or not. + calls uint16 // what depth in mustDecode are we in now. + + _ [6]uint8 // padding + + _ [1]uint64 // padding } func (z *bufioDecReader) reset(r io.Reader, bufsize int) { z.ioDecReaderCommon.reset(r) z.c = 0 + z.calls = 0 if cap(z.buf) >= bufsize { z.buf = z.buf[:0] } else { - z.bytesBufPooler.end() // potentially return old one to pool z.buf = z.bytesBufPooler.get(bufsize)[:0] // z.buf = make([]byte, 0, bufsize) } } +func (z *bufioDecReader) release() { + z.buf = nil + z.bytesBufPooler.end() +} + func (z *bufioDecReader) readb(p []byte) { var n = uint(copy(p, z.buf[z.c:])) z.n += n @@ -2294,12 +2306,7 @@ type Decoder struct { depth int16 maxdepth int16 - // Extensions can call Decode() within a current Decode() call. - // We need to know when the top level Decode() call returns, - // so we can decide whether to Release() or not. - calls uint16 // what depth in mustDecode are we in now. - - _ [2]uint8 // padding + _ [4]uint8 // padding is map[string]string // used for interning strings @@ -2359,7 +2366,6 @@ func (d *Decoder) resetCommon() { // d.r = &d.decReaderSwitch d.d.reset() d.err = nil - d.calls = 0 d.depth = 0 d.maxdepth = d.h.MaxDepth if d.maxdepth <= 0 { @@ -2523,16 +2529,21 @@ func (d *Decoder) MustDecode(v interface{}) { // This provides insight to the code location that triggered the error. func (d *Decoder) mustDecode(v interface{}) { // TODO: Top-level: ensure that v is a pointer and not nil. - d.calls++ if d.d.TryDecodeAsNil() { setZero(v) - } else { + return + } + if d.bi == nil { d.decode(v) + return } + + d.bi.calls++ + d.decode(v) // xprintf(">>>>>>>> >>>>>>>> num decFns: %v\n", d.cf.sn) - d.calls-- - if !d.h.ExplicitRelease && d.calls == 0 { - d.Release() + d.bi.calls-- + if !d.h.ExplicitRelease && d.bi.calls == 0 { + d.bi.release() } } @@ -2558,12 +2569,8 @@ func (d *Decoder) finalize() { // // By default, Release() is automatically called unless the option ExplicitRelease is set. func (d *Decoder) Release() { - if useFinalizers && removeFinalizerOnRelease { - runtime.SetFinalizer(d, nil) - } - if d.bi != nil && d.bi.bytesBufPooler.pool != nil { - d.bi.buf = nil - d.bi.bytesBufPooler.end() + if d.bi != nil { + d.bi.release() } // d.decNakedPooler.end() } diff --git a/vendor/github.com/ugorji/go/codec/encode.go b/vendor/github.com/ugorji/go/codec/encode.go index 6647c67..26b3e4b 100644 --- a/vendor/github.com/ugorji/go/codec/encode.go +++ b/vendor/github.com/ugorji/go/codec/encode.go @@ -12,7 +12,6 @@ import ( "runtime" "sort" "strconv" - "sync" "time" ) @@ -280,10 +279,18 @@ type bufioEncWriter struct { buf []byte w io.Writer n int + sz int // buf size + + // Extensions can call Encode() within a current Encode() call. + // We need to know when the top level Encode() call returns, + // so we can decide whether to Release() or not. + calls uint16 // what depth in mustDecode are we in now. + + _ [6]uint8 // padding bytesBufPooler - _ [3]uint64 // padding + _ [1]uint64 // padding // a int // b [4]byte // err @@ -292,18 +299,24 @@ type bufioEncWriter struct { func (z *bufioEncWriter) reset(w io.Writer, bufsize int) { z.w = w z.n = 0 + z.calls = 0 if bufsize <= 0 { bufsize = defEncByteBufSize } + z.sz = bufsize if cap(z.buf) >= bufsize { z.buf = z.buf[:cap(z.buf)] } else { - z.bytesBufPooler.end() // potentially return old one to pool z.buf = z.bytesBufPooler.get(bufsize) // z.buf = make([]byte, bufsize) } } +func (z *bufioEncWriter) release() { + z.buf = nil + z.bytesBufPooler.end() +} + //go:noinline - flush only called intermittently func (z *bufioEncWriter) flush() { n, err := z.w.Write(z.buf[:z.n]) @@ -731,30 +744,9 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) { // The cost is that of locking sometimes, but sync.Pool is efficient // enough to reduce thread contention. - var spool *sync.Pool - var poolv interface{} - var fkvs []sfiRv // fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen) - if newlen < 0 { // bounds-check-elimination - // cannot happen // here for bounds-check-elimination - } else if newlen <= 8 { - spool, poolv = pool.sfiRv8() - fkvs = poolv.(*[8]sfiRv)[:newlen] - } else if newlen <= 16 { - spool, poolv = pool.sfiRv16() - fkvs = poolv.(*[16]sfiRv)[:newlen] - } else if newlen <= 32 { - spool, poolv = pool.sfiRv32() - fkvs = poolv.(*[32]sfiRv)[:newlen] - } else if newlen <= 64 { - spool, poolv = pool.sfiRv64() - fkvs = poolv.(*[64]sfiRv)[:newlen] - } else if newlen <= 128 { - spool, poolv = pool.sfiRv128() - fkvs = poolv.(*[128]sfiRv)[:newlen] - } else { - fkvs = make([]sfiRv, newlen) - } + var spool sfiRvPooler + var fkvs = spool.get(newlen) var kv sfiRv recur := e.h.RecursiveEmptyCheck @@ -773,7 +765,8 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) { // if a reference or struct, set to nil (so you do not output too much) if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) { switch kv.r.Kind() { - case reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice: + case reflect.Struct, reflect.Interface, reflect.Ptr, + reflect.Array, reflect.Map, reflect.Slice: kv.r = reflect.Value{} //encode as nil } } @@ -842,9 +835,7 @@ func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) { // do not use defer. Instead, use explicit pool return at end of function. // defer has a cost we are trying to avoid. // If there is a panic and these slices are not returned, it is ok. - if spool != nil { - spool.Put(poolv) - } + spool.end() } func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { @@ -1258,12 +1249,7 @@ type Encoder struct { ci set - // Extensions can call Encode() within a current Encode() call. - // We need to know when the top level Encode() call returns, - // so we can decide whether to Release() or not. - calls uint16 // what depth in mustEncode are we in now. - - b [(5 * 8) - 2]byte // for encoding chan or (non-addressable) [N]byte + b [(5 * 8)]byte // for encoding chan or (non-addressable) [N]byte // ---- writable fields during execution --- *try* to keep in sep cache line @@ -1319,7 +1305,6 @@ func (e *Encoder) resetCommon() { _, e.js = e.hh.(*JsonHandle) e.e.reset() e.err = nil - e.calls = 0 } // Reset resets the Encoder with a new output stream. @@ -1494,13 +1479,26 @@ func (e *Encoder) MustEncode(v interface{}) { } func (e *Encoder) mustEncode(v interface{}) { - e.calls++ + if e.wf == nil { + e.encode(v) + e.e.atEndOfEncode() + e.w.end() + return + } + + if e.wf.buf == nil { + e.wf.buf = e.wf.bytesBufPooler.get(e.wf.sz) + } + e.wf.calls++ + e.encode(v) e.e.atEndOfEncode() e.w.end() - e.calls-- - if !e.h.ExplicitRelease && e.calls == 0 { - e.Release() + + e.wf.calls-- + + if !e.h.ExplicitRelease && e.wf.calls == 0 { + e.wf.release() } } @@ -1525,12 +1523,8 @@ func (e *Encoder) finalize() { // It is important to call Release() when done with an Encoder, so those resources // are released instantly for use by subsequently created Encoders. func (e *Encoder) Release() { - if useFinalizers && removeFinalizerOnRelease { - runtime.SetFinalizer(e, nil) - } if e.wf != nil { - e.wf.buf = nil - e.wf.bytesBufPooler.end() + e.wf.release() } } diff --git a/vendor/github.com/ugorji/go/codec/go.mod b/vendor/github.com/ugorji/go/codec/go.mod index ea7ad97..69ab4ea 100644 --- a/vendor/github.com/ugorji/go/codec/go.mod +++ b/vendor/github.com/ugorji/go/codec/go.mod @@ -1,2 +1,3 @@ module github.com/ugorji/go/codec +require github.com/ugorji/go v1.1.2 diff --git a/vendor/github.com/ugorji/go/codec/helper.go b/vendor/github.com/ugorji/go/codec/helper.go index 2c02f9c..8ada846 100644 --- a/vendor/github.com/ugorji/go/codec/helper.go +++ b/vendor/github.com/ugorji/go/codec/helper.go @@ -127,7 +127,7 @@ const ( // arrayCacheLen is the length of the cache used in encoder or decoder for // allowing zero-alloc initialization. - arrayCacheLen = 8 + // arrayCacheLen = 8 // size of the cacheline: defaulting to value for archs: amd64, arm64, 386 // should use "runtime/internal/sys".CacheLineSize, but that is not exposed. @@ -149,8 +149,7 @@ const ( // explicitly call SetFinalizer themselves e.g. // runtime.SetFinalizer(e, (*Encoder).Release) // runtime.SetFinalizer(d, (*Decoder).Release) - useFinalizers = false - removeFinalizerOnRelease = false + useFinalizers = false ) var oneByteArr [1]byte @@ -1598,7 +1597,7 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { } else { ti.keyType = valueTypeString } - pp, pi := pool.tiLoad() + pp, pi := &pool.tiload, pool.tiload.Get() // pool.tiLoad() pv := pi.(*typeInfoLoadArray) pv.etypes[0] = ti.rtid // vv := typeInfoLoad{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]} @@ -2372,21 +2371,21 @@ func (x *bitset256) set(pos byte) { type pooler struct { // function-scoped pooled resources tiload sync.Pool // for type info loading - strRv8, strRv16, strRv32, strRv64, strRv128 sync.Pool // for stringRV + sfiRv8, sfiRv16, sfiRv32, sfiRv64, sfiRv128 sync.Pool // for struct encoding // lifetime-scoped pooled resources // dn sync.Pool // for decNaked - buf1k, buf2k, buf4k, buf8k, buf16k sync.Pool // for [N]byte + buf1k, buf2k, buf4k, buf8k, buf16k, buf32k, buf64k sync.Pool // for [N]byte } func (p *pooler) init() { p.tiload.New = func() interface{} { return new(typeInfoLoadArray) } - p.strRv8.New = func() interface{} { return new([8]sfiRv) } - p.strRv16.New = func() interface{} { return new([16]sfiRv) } - p.strRv32.New = func() interface{} { return new([32]sfiRv) } - p.strRv64.New = func() interface{} { return new([64]sfiRv) } - p.strRv128.New = func() interface{} { return new([128]sfiRv) } + p.sfiRv8.New = func() interface{} { return new([8]sfiRv) } + p.sfiRv16.New = func() interface{} { return new([16]sfiRv) } + p.sfiRv32.New = func() interface{} { return new([32]sfiRv) } + p.sfiRv64.New = func() interface{} { return new([64]sfiRv) } + p.sfiRv128.New = func() interface{} { return new([128]sfiRv) } // p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x } @@ -2395,43 +2394,52 @@ func (p *pooler) init() { p.buf4k.New = func() interface{} { return new([4 * 1024]byte) } p.buf8k.New = func() interface{} { return new([8 * 1024]byte) } p.buf16k.New = func() interface{} { return new([16 * 1024]byte) } + p.buf32k.New = func() interface{} { return new([32 * 1024]byte) } + p.buf64k.New = func() interface{} { return new([64 * 1024]byte) } } -func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) { - return &p.strRv8, p.strRv8.Get() -} -func (p *pooler) sfiRv16() (sp *sync.Pool, v interface{}) { - return &p.strRv16, p.strRv16.Get() -} -func (p *pooler) sfiRv32() (sp *sync.Pool, v interface{}) { - return &p.strRv32, p.strRv32.Get() -} -func (p *pooler) sfiRv64() (sp *sync.Pool, v interface{}) { - return &p.strRv64, p.strRv64.Get() -} -func (p *pooler) sfiRv128() (sp *sync.Pool, v interface{}) { - return &p.strRv128, p.strRv128.Get() -} +// func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) { +// return &p.strRv8, p.strRv8.Get() +// } +// func (p *pooler) sfiRv16() (sp *sync.Pool, v interface{}) { +// return &p.strRv16, p.strRv16.Get() +// } +// func (p *pooler) sfiRv32() (sp *sync.Pool, v interface{}) { +// return &p.strRv32, p.strRv32.Get() +// } +// func (p *pooler) sfiRv64() (sp *sync.Pool, v interface{}) { +// return &p.strRv64, p.strRv64.Get() +// } +// func (p *pooler) sfiRv128() (sp *sync.Pool, v interface{}) { +// return &p.strRv128, p.strRv128.Get() +// } -func (p *pooler) bytes1k() (sp *sync.Pool, v interface{}) { - return &p.buf1k, p.buf1k.Get() -} -func (p *pooler) bytes2k() (sp *sync.Pool, v interface{}) { - return &p.buf2k, p.buf2k.Get() -} -func (p *pooler) bytes4k() (sp *sync.Pool, v interface{}) { - return &p.buf4k, p.buf4k.Get() -} -func (p *pooler) bytes8k() (sp *sync.Pool, v interface{}) { - return &p.buf8k, p.buf8k.Get() -} -func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) { - return &p.buf16k, p.buf16k.Get() -} -func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) { - return &p.tiload, p.tiload.Get() -} +// func (p *pooler) bytes1k() (sp *sync.Pool, v interface{}) { +// return &p.buf1k, p.buf1k.Get() +// } +// func (p *pooler) bytes2k() (sp *sync.Pool, v interface{}) { +// return &p.buf2k, p.buf2k.Get() +// } +// func (p *pooler) bytes4k() (sp *sync.Pool, v interface{}) { +// return &p.buf4k, p.buf4k.Get() +// } +// func (p *pooler) bytes8k() (sp *sync.Pool, v interface{}) { +// return &p.buf8k, p.buf8k.Get() +// } +// func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) { +// return &p.buf16k, p.buf16k.Get() +// } +// func (p *pooler) bytes32k() (sp *sync.Pool, v interface{}) { +// return &p.buf32k, p.buf32k.Get() +// } +// func (p *pooler) bytes64k() (sp *sync.Pool, v interface{}) { +// return &p.buf64k, p.buf64k.Get() +// } + +// func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) { +// return &p.tiload, p.tiload.Get() +// } // func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) { // return &p.dn, p.dn.Get() @@ -2534,21 +2542,105 @@ func (z *bytesBufPooler) end() { } func (z *bytesBufPooler) get(bufsize int) (buf []byte) { + // ensure an end is called first (if necessary) + if z.pool != nil { + z.pool.Put(z.poolbuf) + z.pool, z.poolbuf = nil, nil + } + + // // Try to use binary search. + // // This is not optimal, as most folks select 1k or 2k buffers + // // so a linear search is better (sequence of if/else blocks) + // if bufsize < 1 { + // bufsize = 0 + // } else { + // bufsize-- + // bufsize /= 1024 + // } + // switch bufsize { + // case 0: + // z.pool, z.poolbuf = pool.bytes1k() + // buf = z.poolbuf.(*[1 * 1024]byte)[:] + // case 1: + // z.pool, z.poolbuf = pool.bytes2k() + // buf = z.poolbuf.(*[2 * 1024]byte)[:] + // case 2, 3: + // z.pool, z.poolbuf = pool.bytes4k() + // buf = z.poolbuf.(*[4 * 1024]byte)[:] + // case 4, 5, 6, 7: + // z.pool, z.poolbuf = pool.bytes8k() + // buf = z.poolbuf.(*[8 * 1024]byte)[:] + // case 8, 9, 10, 11, 12, 13, 14, 15: + // z.pool, z.poolbuf = pool.bytes16k() + // buf = z.poolbuf.(*[16 * 1024]byte)[:] + // case 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31: + // z.pool, z.poolbuf = pool.bytes32k() + // buf = z.poolbuf.(*[32 * 1024]byte)[:] + // default: + // z.pool, z.poolbuf = pool.bytes64k() + // buf = z.poolbuf.(*[64 * 1024]byte)[:] + // } + // return + if bufsize <= 1*1024 { - z.pool, z.poolbuf = pool.bytes1k() + z.pool, z.poolbuf = &pool.buf1k, pool.buf1k.Get() // pool.bytes1k() buf = z.poolbuf.(*[1 * 1024]byte)[:] } else if bufsize <= 2*1024 { - z.pool, z.poolbuf = pool.bytes2k() + z.pool, z.poolbuf = &pool.buf2k, pool.buf2k.Get() // pool.bytes2k() buf = z.poolbuf.(*[2 * 1024]byte)[:] } else if bufsize <= 4*1024 { - z.pool, z.poolbuf = pool.bytes4k() + z.pool, z.poolbuf = &pool.buf4k, pool.buf4k.Get() // pool.bytes4k() buf = z.poolbuf.(*[4 * 1024]byte)[:] } else if bufsize <= 8*1024 { - z.pool, z.poolbuf = pool.bytes8k() + z.pool, z.poolbuf = &pool.buf8k, pool.buf8k.Get() // pool.bytes8k() buf = z.poolbuf.(*[8 * 1024]byte)[:] - } else { - z.pool, z.poolbuf = pool.bytes16k() + } else if bufsize <= 16*1024 { + z.pool, z.poolbuf = &pool.buf16k, pool.buf16k.Get() // pool.bytes16k() buf = z.poolbuf.(*[16 * 1024]byte)[:] + } else if bufsize <= 32*1024 { + z.pool, z.poolbuf = &pool.buf32k, pool.buf32k.Get() // pool.bytes32k() + buf = z.poolbuf.(*[32 * 1024]byte)[:] + } else { + z.pool, z.poolbuf = &pool.buf64k, pool.buf64k.Get() // pool.bytes64k() + buf = z.poolbuf.(*[64 * 1024]byte)[:] + } + return +} + +// ---------------- + +type sfiRvPooler struct { + pool *sync.Pool + poolv interface{} +} + +func (z *sfiRvPooler) end() { + if z.pool != nil { + z.pool.Put(z.poolv) + z.pool, z.poolv = nil, nil + } +} + +func (z *sfiRvPooler) get(newlen int) (fkvs []sfiRv) { + if newlen < 0 { // bounds-check-elimination + // cannot happen // here for bounds-check-elimination + } else if newlen <= 8 { + z.pool, z.poolv = &pool.sfiRv8, pool.sfiRv8.Get() // pool.sfiRv8() + fkvs = z.poolv.(*[8]sfiRv)[:newlen] + } else if newlen <= 16 { + z.pool, z.poolv = &pool.sfiRv16, pool.sfiRv16.Get() // pool.sfiRv16() + fkvs = z.poolv.(*[16]sfiRv)[:newlen] + } else if newlen <= 32 { + z.pool, z.poolv = &pool.sfiRv32, pool.sfiRv32.Get() // pool.sfiRv32() + fkvs = z.poolv.(*[32]sfiRv)[:newlen] + } else if newlen <= 64 { + z.pool, z.poolv = &pool.sfiRv64, pool.sfiRv64.Get() // pool.sfiRv64() + fkvs = z.poolv.(*[64]sfiRv)[:newlen] + } else if newlen <= 128 { + z.pool, z.poolv = &pool.sfiRv128, pool.sfiRv128.Get() // pool.sfiRv128() + fkvs = z.poolv.(*[128]sfiRv)[:newlen] + } else { + fkvs = make([]sfiRv, newlen) } return } diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 2c1cade..633ee15 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -177,7 +177,7 @@ func (s *nodeStack) index(n *Node) int { // contains returns whether a is within s. func (s *nodeStack) contains(a atom.Atom) bool { for _, n := range *s { - if n.DataAtom == a { + if n.DataAtom == a && n.Namespace == "" { return true } } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 64a5793..ca2cb58 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -439,9 +439,6 @@ func (p *parser) resetInsertionMode() { case a.Select: if !last { for ancestor, first := n, p.oe[0]; ancestor != first; { - if ancestor == first { - break - } ancestor = p.oe[p.oe.index(ancestor)-1] switch ancestor.DataAtom { case a.Template: @@ -1719,8 +1716,12 @@ func inSelectIM(p *parser) bool { } p.addElement() case a.Select: - p.tok.Type = EndTagToken - return false + if p.popUntil(selectScope, a.Select) { + p.resetInsertionMode() + } else { + // Ignore the token. + return true + } case a.Input, a.Keygen, a.Textarea: if p.elementInScope(selectScope, a.Select) { p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) @@ -1750,6 +1751,9 @@ func inSelectIM(p *parser) bool { case a.Select: if p.popUntil(selectScope, a.Select) { p.resetInsertionMode() + } else { + // Ignore the token. + return true } case a.Template: return inHeadIM(p) @@ -1775,13 +1779,22 @@ func inSelectInTableIM(p *parser) bool { case StartTagToken, EndTagToken: switch p.tok.DataAtom { case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th: - if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) { - p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) - return false - } else { + if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) { // Ignore the token. return true } + // This is like p.popUntil(selectScope, a.Select), but it also + // matches , not just