diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/google.golang.org/grpc | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/google.golang.org/grpc')
102 files changed, 16140 insertions, 6970 deletions
diff --git a/vendor/google.golang.org/grpc/.travis.yml b/vendor/google.golang.org/grpc/.travis.yml index 88a785d..f443eec 100644 --- a/vendor/google.golang.org/grpc/.travis.yml +++ b/vendor/google.golang.org/grpc/.travis.yml | |||
@@ -1,21 +1,37 @@ | |||
1 | language: go | 1 | language: go |
2 | 2 | ||
3 | go: | 3 | matrix: |
4 | - 1.6.x | 4 | include: |
5 | - 1.7.x | 5 | - go: 1.11.x |
6 | - 1.8.x | 6 | env: VET=1 GO111MODULE=on |
7 | - go: 1.11.x | ||
8 | env: RACE=1 GO111MODULE=on | ||
9 | - go: 1.11.x | ||
10 | env: RUN386=1 | ||
11 | - go: 1.11.x | ||
12 | env: GRPC_GO_RETRY=on | ||
13 | - go: 1.10.x | ||
14 | - go: 1.9.x | ||
15 | - go: 1.9.x | ||
16 | env: GAE=1 | ||
7 | 17 | ||
8 | go_import_path: google.golang.org/grpc | 18 | go_import_path: google.golang.org/grpc |
9 | 19 | ||
10 | before_install: | 20 | before_install: |
11 | - if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then go get -u github.com/golang/lint/golint honnef.co/go/tools/cmd/staticcheck; fi | 21 | - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi |
12 | - go get -u golang.org/x/tools/cmd/goimports github.com/axw/gocov/gocov github.com/mattn/goveralls golang.org/x/tools/cmd/cover | 22 | - if [[ -n "${RUN386}" ]]; then export GOARCH=386; fi |
23 | - if [[ "${TRAVIS_EVENT_TYPE}" = "cron" && -z "${RUN386}" ]]; then RACE=1; fi | ||
24 | - if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then VET_SKIP_PROTO=1; fi | ||
25 | |||
26 | install: | ||
27 | - try3() { eval "$*" || eval "$*" || eval "$*"; } | ||
28 | - try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi' | ||
29 | - if [[ "${GAE}" = 1 ]]; then source ./install_gae.sh; make testappenginedeps; fi | ||
30 | - if [[ "${VET}" = 1 ]]; then ./vet.sh -install; fi | ||
13 | 31 | ||
14 | script: | 32 | script: |
15 | - 'set -o pipefail && git ls-files "*.go" | xargs grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" 2>&1 | tee /dev/stderr | (! read)' | 33 | - set -e |
16 | - 'set -o pipefail && gofmt -s -d -l . 2>&1 | tee /dev/stderr | (! read)' | 34 | - if [[ "${VET}" = 1 ]]; then ./vet.sh; fi |
17 | - 'set -o pipefail && goimports -l . 2>&1 | tee /dev/stderr | (! read)' | 35 | - if [[ "${GAE}" = 1 ]]; then make testappengine; exit 0; fi |
18 | - 'if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then ! golint ./... | grep -vE "(_mock|_string|\.pb)\.go:"; fi' | 36 | - if [[ "${RACE}" = 1 ]]; then make testrace; exit 0; fi |
19 | - 'if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then ! go tool vet -all . 2>&1 | grep -vF .pb.go:; fi' # https://github.com/golang/protobuf/issues/214 | 37 | - make test |
20 | - make test testrace | ||
21 | - 'if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then staticcheck -ignore google.golang.org/grpc/transport/transport_test.go:SA2002 ./...; fi' # TODO(menghanl): fix these | ||
diff --git a/vendor/google.golang.org/grpc/CONTRIBUTING.md b/vendor/google.golang.org/grpc/CONTRIBUTING.md index a5c6e06..0863eb2 100644 --- a/vendor/google.golang.org/grpc/CONTRIBUTING.md +++ b/vendor/google.golang.org/grpc/CONTRIBUTING.md | |||
@@ -7,7 +7,7 @@ If you are new to github, please start by reading [Pull Request howto](https://h | |||
7 | ## Legal requirements | 7 | ## Legal requirements |
8 | 8 | ||
9 | In order to protect both you and ourselves, you will need to sign the | 9 | In order to protect both you and ourselves, you will need to sign the |
10 | [Contributor License Agreement](https://cla.developers.google.com/clas). | 10 | [Contributor License Agreement](https://identity.linuxfoundation.org/projects/cncf). |
11 | 11 | ||
12 | ## Guidelines for Pull Requests | 12 | ## Guidelines for Pull Requests |
13 | How to get your contributions merged smoothly and quickly. | 13 | How to get your contributions merged smoothly and quickly. |
@@ -27,6 +27,10 @@ How to get your contributions merged smoothly and quickly. | |||
27 | - Keep your PR up to date with upstream/master (if there are merge conflicts, we can't really merge your change). | 27 | - Keep your PR up to date with upstream/master (if there are merge conflicts, we can't really merge your change). |
28 | 28 | ||
29 | - **All tests need to be passing** before your change can be merged. We recommend you **run tests locally** before creating your PR to catch breakages early on. | 29 | - **All tests need to be passing** before your change can be merged. We recommend you **run tests locally** before creating your PR to catch breakages early on. |
30 | - `make all` to test everything, OR | ||
31 | - `make vet` to catch vet errors | ||
32 | - `make test` to run the tests | ||
33 | - `make testrace` to run tests in race mode | ||
30 | 34 | ||
31 | - Exceptions to the rules can be made if there's a compelling reason for doing so. | 35 | - Exceptions to the rules can be made if there's a compelling reason for doing so. |
32 | 36 | ||
diff --git a/vendor/google.golang.org/grpc/Makefile b/vendor/google.golang.org/grpc/Makefile index 03bb01f..41a754f 100644 --- a/vendor/google.golang.org/grpc/Makefile +++ b/vendor/google.golang.org/grpc/Makefile | |||
@@ -1,52 +1,60 @@ | |||
1 | all: test testrace | 1 | all: vet test testrace testappengine |
2 | |||
3 | deps: | ||
4 | go get -d -v google.golang.org/grpc/... | ||
5 | |||
6 | updatedeps: | ||
7 | go get -d -v -u -f google.golang.org/grpc/... | ||
8 | |||
9 | testdeps: | ||
10 | go get -d -v -t google.golang.org/grpc/... | ||
11 | |||
12 | updatetestdeps: | ||
13 | go get -d -v -t -u -f google.golang.org/grpc/... | ||
14 | 2 | ||
15 | build: deps | 3 | build: deps |
16 | go build google.golang.org/grpc/... | 4 | go build google.golang.org/grpc/... |
17 | 5 | ||
6 | clean: | ||
7 | go clean -i google.golang.org/grpc/... | ||
8 | |||
9 | deps: | ||
10 | go get -d -v google.golang.org/grpc/... | ||
11 | |||
18 | proto: | 12 | proto: |
19 | @ if ! which protoc > /dev/null; then \ | 13 | @ if ! which protoc > /dev/null; then \ |
20 | echo "error: protoc not installed" >&2; \ | 14 | echo "error: protoc not installed" >&2; \ |
21 | exit 1; \ | 15 | exit 1; \ |
22 | fi | 16 | fi |
23 | go get -u -v github.com/golang/protobuf/protoc-gen-go | 17 | go generate google.golang.org/grpc/... |
24 | # use $$dir as the root for all proto files in the same directory | ||
25 | for dir in $$(git ls-files '*.proto' | xargs -n1 dirname | uniq); do \ | ||
26 | protoc -I $$dir --go_out=plugins=grpc:$$dir $$dir/*.proto; \ | ||
27 | done | ||
28 | 18 | ||
29 | test: testdeps | 19 | test: testdeps |
30 | go test -v -cpu 1,4 google.golang.org/grpc/... | 20 | go test -cpu 1,4 -timeout 7m google.golang.org/grpc/... |
21 | |||
22 | testappengine: testappenginedeps | ||
23 | goapp test -cpu 1,4 -timeout 7m google.golang.org/grpc/... | ||
24 | |||
25 | testappenginedeps: | ||
26 | goapp get -d -v -t -tags 'appengine appenginevm' google.golang.org/grpc/... | ||
27 | |||
28 | testdeps: | ||
29 | go get -d -v -t google.golang.org/grpc/... | ||
31 | 30 | ||
32 | testrace: testdeps | 31 | testrace: testdeps |
33 | go test -v -race -cpu 1,4 google.golang.org/grpc/... | 32 | go test -race -cpu 1,4 -timeout 7m google.golang.org/grpc/... |
34 | 33 | ||
35 | clean: | 34 | updatedeps: |
36 | go clean -i google.golang.org/grpc/... | 35 | go get -d -v -u -f google.golang.org/grpc/... |
36 | |||
37 | updatetestdeps: | ||
38 | go get -d -v -t -u -f google.golang.org/grpc/... | ||
39 | |||
40 | vet: vetdeps | ||
41 | ./vet.sh | ||
37 | 42 | ||
38 | coverage: testdeps | 43 | vetdeps: |
39 | ./coverage.sh --coveralls | 44 | ./vet.sh -install |
40 | 45 | ||
41 | .PHONY: \ | 46 | .PHONY: \ |
42 | all \ | 47 | all \ |
43 | deps \ | ||
44 | updatedeps \ | ||
45 | testdeps \ | ||
46 | updatetestdeps \ | ||
47 | build \ | 48 | build \ |
49 | clean \ | ||
50 | deps \ | ||
48 | proto \ | 51 | proto \ |
49 | test \ | 52 | test \ |
53 | testappengine \ | ||
54 | testappenginedeps \ | ||
55 | testdeps \ | ||
50 | testrace \ | 56 | testrace \ |
51 | clean \ | 57 | updatedeps \ |
52 | coverage | 58 | updatetestdeps \ |
59 | vet \ | ||
60 | vetdeps | ||
diff --git a/vendor/google.golang.org/grpc/README.md b/vendor/google.golang.org/grpc/README.md index 72c7325..e3fb3c7 100644 --- a/vendor/google.golang.org/grpc/README.md +++ b/vendor/google.golang.org/grpc/README.md | |||
@@ -1,6 +1,6 @@ | |||
1 | # gRPC-Go | 1 | # gRPC-Go |
2 | 2 | ||
3 | [![Build Status](https://travis-ci.org/grpc/grpc-go.svg)](https://travis-ci.org/grpc/grpc-go) [![GoDoc](https://godoc.org/google.golang.org/grpc?status.svg)](https://godoc.org/google.golang.org/grpc) | 3 | [![Build Status](https://travis-ci.org/grpc/grpc-go.svg)](https://travis-ci.org/grpc/grpc-go) [![GoDoc](https://godoc.org/google.golang.org/grpc?status.svg)](https://godoc.org/google.golang.org/grpc) [![GoReportCard](https://goreportcard.com/badge/grpc/grpc-go)](https://goreportcard.com/report/github.com/grpc/grpc-go) |
4 | 4 | ||
5 | The Go implementation of [gRPC](https://grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the [gRPC Quick Start: Go](https://grpc.io/docs/quickstart/go.html) guide. | 5 | The Go implementation of [gRPC](https://grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the [gRPC Quick Start: Go](https://grpc.io/docs/quickstart/go.html) guide. |
6 | 6 | ||
@@ -10,13 +10,13 @@ Installation | |||
10 | To install this package, you need to install Go and setup your Go workspace on your computer. The simplest way to install the library is to run: | 10 | To install this package, you need to install Go and setup your Go workspace on your computer. The simplest way to install the library is to run: |
11 | 11 | ||
12 | ``` | 12 | ``` |
13 | $ go get google.golang.org/grpc | 13 | $ go get -u google.golang.org/grpc |
14 | ``` | 14 | ``` |
15 | 15 | ||
16 | Prerequisites | 16 | Prerequisites |
17 | ------------- | 17 | ------------- |
18 | 18 | ||
19 | This requires Go 1.6 or later. | 19 | gRPC-Go requires Go 1.9 or later. |
20 | 20 | ||
21 | Constraints | 21 | Constraints |
22 | ----------- | 22 | ----------- |
@@ -43,3 +43,25 @@ Please update proto package, gRPC package and rebuild the proto files: | |||
43 | - `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}` | 43 | - `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}` |
44 | - `go get -u google.golang.org/grpc` | 44 | - `go get -u google.golang.org/grpc` |
45 | - `protoc --go_out=plugins=grpc:. *.proto` | 45 | - `protoc --go_out=plugins=grpc:. *.proto` |
46 | |||
47 | #### How to turn on logging | ||
48 | |||
49 | The default logger is controlled by the environment variables. Turn everything | ||
50 | on by setting: | ||
51 | |||
52 | ``` | ||
53 | GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info | ||
54 | ``` | ||
55 | |||
56 | #### The RPC failed with error `"code = Unavailable desc = transport is closing"` | ||
57 | |||
58 | This error means the connection the RPC is using was closed, and there are many | ||
59 | possible reasons, including: | ||
60 | 1. mis-configured transport credentials, connection failed on handshaking | ||
61 | 1. bytes disrupted, possibly by a proxy in between | ||
62 | 1. server shutdown | ||
63 | |||
64 | It can be tricky to debug this because the error happens on the client side but | ||
65 | the root cause of the connection being closed is on the server side. Turn on | ||
66 | logging on __both client and server__, and see if there are any transport | ||
67 | errors. | ||
diff --git a/vendor/google.golang.org/grpc/backoff.go b/vendor/google.golang.org/grpc/backoff.go index 090fbe8..fa31565 100644 --- a/vendor/google.golang.org/grpc/backoff.go +++ b/vendor/google.golang.org/grpc/backoff.go | |||
@@ -16,83 +16,23 @@ | |||
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | // See internal/backoff package for the backoff implementation. This file is | ||
20 | // kept for the exported types and API backward compatility. | ||
21 | |||
19 | package grpc | 22 | package grpc |
20 | 23 | ||
21 | import ( | 24 | import ( |
22 | "math/rand" | ||
23 | "time" | 25 | "time" |
24 | ) | 26 | ) |
25 | 27 | ||
26 | // DefaultBackoffConfig uses values specified for backoff in | 28 | // DefaultBackoffConfig uses values specified for backoff in |
27 | // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. | 29 | // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. |
28 | var ( | 30 | var DefaultBackoffConfig = BackoffConfig{ |
29 | DefaultBackoffConfig = BackoffConfig{ | 31 | MaxDelay: 120 * time.Second, |
30 | MaxDelay: 120 * time.Second, | ||
31 | baseDelay: 1.0 * time.Second, | ||
32 | factor: 1.6, | ||
33 | jitter: 0.2, | ||
34 | } | ||
35 | ) | ||
36 | |||
37 | // backoffStrategy defines the methodology for backing off after a grpc | ||
38 | // connection failure. | ||
39 | // | ||
40 | // This is unexported until the gRPC project decides whether or not to allow | ||
41 | // alternative backoff strategies. Once a decision is made, this type and its | ||
42 | // method may be exported. | ||
43 | type backoffStrategy interface { | ||
44 | // backoff returns the amount of time to wait before the next retry given | ||
45 | // the number of consecutive failures. | ||
46 | backoff(retries int) time.Duration | ||
47 | } | 32 | } |
48 | 33 | ||
49 | // BackoffConfig defines the parameters for the default gRPC backoff strategy. | 34 | // BackoffConfig defines the parameters for the default gRPC backoff strategy. |
50 | type BackoffConfig struct { | 35 | type BackoffConfig struct { |
51 | // MaxDelay is the upper bound of backoff delay. | 36 | // MaxDelay is the upper bound of backoff delay. |
52 | MaxDelay time.Duration | 37 | MaxDelay time.Duration |
53 | |||
54 | // TODO(stevvooe): The following fields are not exported, as allowing | ||
55 | // changes would violate the current gRPC specification for backoff. If | ||
56 | // gRPC decides to allow more interesting backoff strategies, these fields | ||
57 | // may be opened up in the future. | ||
58 | |||
59 | // baseDelay is the amount of time to wait before retrying after the first | ||
60 | // failure. | ||
61 | baseDelay time.Duration | ||
62 | |||
63 | // factor is applied to the backoff after each retry. | ||
64 | factor float64 | ||
65 | |||
66 | // jitter provides a range to randomize backoff delays. | ||
67 | jitter float64 | ||
68 | } | ||
69 | |||
70 | func setDefaults(bc *BackoffConfig) { | ||
71 | md := bc.MaxDelay | ||
72 | *bc = DefaultBackoffConfig | ||
73 | |||
74 | if md > 0 { | ||
75 | bc.MaxDelay = md | ||
76 | } | ||
77 | } | ||
78 | |||
79 | func (bc BackoffConfig) backoff(retries int) time.Duration { | ||
80 | if retries == 0 { | ||
81 | return bc.baseDelay | ||
82 | } | ||
83 | backoff, max := float64(bc.baseDelay), float64(bc.MaxDelay) | ||
84 | for backoff < max && retries > 0 { | ||
85 | backoff *= bc.factor | ||
86 | retries-- | ||
87 | } | ||
88 | if backoff > max { | ||
89 | backoff = max | ||
90 | } | ||
91 | // Randomize backoff delays so that if a cluster of requests start at | ||
92 | // the same time, they won't operate in lockstep. | ||
93 | backoff *= 1 + bc.jitter*(rand.Float64()*2-1) | ||
94 | if backoff < 0 { | ||
95 | return 0 | ||
96 | } | ||
97 | return time.Duration(backoff) | ||
98 | } | 38 | } |
diff --git a/vendor/google.golang.org/grpc/balancer.go b/vendor/google.golang.org/grpc/balancer.go index cde472c..a78e702 100644 --- a/vendor/google.golang.org/grpc/balancer.go +++ b/vendor/google.golang.org/grpc/balancer.go | |||
@@ -19,19 +19,20 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "fmt" | 22 | "context" |
23 | "net" | 23 | "net" |
24 | "sync" | 24 | "sync" |
25 | 25 | ||
26 | "golang.org/x/net/context" | ||
27 | "google.golang.org/grpc/codes" | 26 | "google.golang.org/grpc/codes" |
28 | "google.golang.org/grpc/credentials" | 27 | "google.golang.org/grpc/credentials" |
29 | "google.golang.org/grpc/grpclog" | 28 | "google.golang.org/grpc/grpclog" |
30 | "google.golang.org/grpc/naming" | 29 | "google.golang.org/grpc/naming" |
30 | "google.golang.org/grpc/status" | ||
31 | ) | 31 | ) |
32 | 32 | ||
33 | // Address represents a server the client connects to. | 33 | // Address represents a server the client connects to. |
34 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | 34 | // |
35 | // Deprecated: please use package balancer. | ||
35 | type Address struct { | 36 | type Address struct { |
36 | // Addr is the server address on which a connection will be established. | 37 | // Addr is the server address on which a connection will be established. |
37 | Addr string | 38 | Addr string |
@@ -41,6 +42,8 @@ type Address struct { | |||
41 | } | 42 | } |
42 | 43 | ||
43 | // BalancerConfig specifies the configurations for Balancer. | 44 | // BalancerConfig specifies the configurations for Balancer. |
45 | // | ||
46 | // Deprecated: please use package balancer. | ||
44 | type BalancerConfig struct { | 47 | type BalancerConfig struct { |
45 | // DialCreds is the transport credential the Balancer implementation can | 48 | // DialCreds is the transport credential the Balancer implementation can |
46 | // use to dial to a remote load balancer server. The Balancer implementations | 49 | // use to dial to a remote load balancer server. The Balancer implementations |
@@ -53,7 +56,8 @@ type BalancerConfig struct { | |||
53 | } | 56 | } |
54 | 57 | ||
55 | // BalancerGetOptions configures a Get call. | 58 | // BalancerGetOptions configures a Get call. |
56 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | 59 | // |
60 | // Deprecated: please use package balancer. | ||
57 | type BalancerGetOptions struct { | 61 | type BalancerGetOptions struct { |
58 | // BlockingWait specifies whether Get should block when there is no | 62 | // BlockingWait specifies whether Get should block when there is no |
59 | // connected address. | 63 | // connected address. |
@@ -61,7 +65,8 @@ type BalancerGetOptions struct { | |||
61 | } | 65 | } |
62 | 66 | ||
63 | // Balancer chooses network addresses for RPCs. | 67 | // Balancer chooses network addresses for RPCs. |
64 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | 68 | // |
69 | // Deprecated: please use package balancer. | ||
65 | type Balancer interface { | 70 | type Balancer interface { |
66 | // Start does the initialization work to bootstrap a Balancer. For example, | 71 | // Start does the initialization work to bootstrap a Balancer. For example, |
67 | // this function may start the name resolution and watch the updates. It will | 72 | // this function may start the name resolution and watch the updates. It will |
@@ -112,28 +117,10 @@ type Balancer interface { | |||
112 | Close() error | 117 | Close() error |
113 | } | 118 | } |
114 | 119 | ||
115 | // downErr implements net.Error. It is constructed by gRPC internals and passed to the down | ||
116 | // call of Balancer. | ||
117 | type downErr struct { | ||
118 | timeout bool | ||
119 | temporary bool | ||
120 | desc string | ||
121 | } | ||
122 | |||
123 | func (e downErr) Error() string { return e.desc } | ||
124 | func (e downErr) Timeout() bool { return e.timeout } | ||
125 | func (e downErr) Temporary() bool { return e.temporary } | ||
126 | |||
127 | func downErrorf(timeout, temporary bool, format string, a ...interface{}) downErr { | ||
128 | return downErr{ | ||
129 | timeout: timeout, | ||
130 | temporary: temporary, | ||
131 | desc: fmt.Sprintf(format, a...), | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch | 120 | // RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch |
136 | // the name resolution updates and updates the addresses available correspondingly. | 121 | // the name resolution updates and updates the addresses available correspondingly. |
122 | // | ||
123 | // Deprecated: please use package balancer/roundrobin. | ||
137 | func RoundRobin(r naming.Resolver) Balancer { | 124 | func RoundRobin(r naming.Resolver) Balancer { |
138 | return &roundRobin{r: r} | 125 | return &roundRobin{r: r} |
139 | } | 126 | } |
@@ -310,7 +297,7 @@ func (rr *roundRobin) Get(ctx context.Context, opts BalancerGetOptions) (addr Ad | |||
310 | if !opts.BlockingWait { | 297 | if !opts.BlockingWait { |
311 | if len(rr.addrs) == 0 { | 298 | if len(rr.addrs) == 0 { |
312 | rr.mu.Unlock() | 299 | rr.mu.Unlock() |
313 | err = Errorf(codes.Unavailable, "there is no address available") | 300 | err = status.Errorf(codes.Unavailable, "there is no address available") |
314 | return | 301 | return |
315 | } | 302 | } |
316 | // Returns the next addr on rr.addrs for failfast RPCs. | 303 | // Returns the next addr on rr.addrs for failfast RPCs. |
@@ -395,3 +382,10 @@ func (rr *roundRobin) Close() error { | |||
395 | } | 382 | } |
396 | return nil | 383 | return nil |
397 | } | 384 | } |
385 | |||
386 | // pickFirst is used to test multi-addresses in one addrConn in which all addresses share the same addrConn. | ||
387 | // It is a wrapper around roundRobin balancer. The logic of all methods works fine because balancer.Get() | ||
388 | // returns the only address Up by resetTransport(). | ||
389 | type pickFirst struct { | ||
390 | *roundRobin | ||
391 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go new file mode 100644 index 0000000..317c2e7 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/balancer.go | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package balancer defines APIs for load balancing in gRPC. | ||
20 | // All APIs in this package are experimental. | ||
21 | package balancer | ||
22 | |||
23 | import ( | ||
24 | "context" | ||
25 | "errors" | ||
26 | "net" | ||
27 | "strings" | ||
28 | |||
29 | "google.golang.org/grpc/connectivity" | ||
30 | "google.golang.org/grpc/credentials" | ||
31 | "google.golang.org/grpc/internal" | ||
32 | "google.golang.org/grpc/metadata" | ||
33 | "google.golang.org/grpc/resolver" | ||
34 | ) | ||
35 | |||
36 | var ( | ||
37 | // m is a map from name to balancer builder. | ||
38 | m = make(map[string]Builder) | ||
39 | ) | ||
40 | |||
41 | // Register registers the balancer builder to the balancer map. b.Name | ||
42 | // (lowercased) will be used as the name registered with this builder. | ||
43 | // | ||
44 | // NOTE: this function must only be called during initialization time (i.e. in | ||
45 | // an init() function), and is not thread-safe. If multiple Balancers are | ||
46 | // registered with the same name, the one registered last will take effect. | ||
47 | func Register(b Builder) { | ||
48 | m[strings.ToLower(b.Name())] = b | ||
49 | } | ||
50 | |||
51 | // unregisterForTesting deletes the balancer with the given name from the | ||
52 | // balancer map. | ||
53 | // | ||
54 | // This function is not thread-safe. | ||
55 | func unregisterForTesting(name string) { | ||
56 | delete(m, name) | ||
57 | } | ||
58 | |||
59 | func init() { | ||
60 | internal.BalancerUnregister = unregisterForTesting | ||
61 | } | ||
62 | |||
63 | // Get returns the resolver builder registered with the given name. | ||
64 | // Note that the compare is done in a case-insenstive fashion. | ||
65 | // If no builder is register with the name, nil will be returned. | ||
66 | func Get(name string) Builder { | ||
67 | if b, ok := m[strings.ToLower(name)]; ok { | ||
68 | return b | ||
69 | } | ||
70 | return nil | ||
71 | } | ||
72 | |||
73 | // SubConn represents a gRPC sub connection. | ||
74 | // Each sub connection contains a list of addresses. gRPC will | ||
75 | // try to connect to them (in sequence), and stop trying the | ||
76 | // remainder once one connection is successful. | ||
77 | // | ||
78 | // The reconnect backoff will be applied on the list, not a single address. | ||
79 | // For example, try_on_all_addresses -> backoff -> try_on_all_addresses. | ||
80 | // | ||
81 | // All SubConns start in IDLE, and will not try to connect. To trigger | ||
82 | // the connecting, Balancers must call Connect. | ||
83 | // When the connection encounters an error, it will reconnect immediately. | ||
84 | // When the connection becomes IDLE, it will not reconnect unless Connect is | ||
85 | // called. | ||
86 | // | ||
87 | // This interface is to be implemented by gRPC. Users should not need a | ||
88 | // brand new implementation of this interface. For the situations like | ||
89 | // testing, the new implementation should embed this interface. This allows | ||
90 | // gRPC to add new methods to this interface. | ||
91 | type SubConn interface { | ||
92 | // UpdateAddresses updates the addresses used in this SubConn. | ||
93 | // gRPC checks if currently-connected address is still in the new list. | ||
94 | // If it's in the list, the connection will be kept. | ||
95 | // If it's not in the list, the connection will gracefully closed, and | ||
96 | // a new connection will be created. | ||
97 | // | ||
98 | // This will trigger a state transition for the SubConn. | ||
99 | UpdateAddresses([]resolver.Address) | ||
100 | // Connect starts the connecting for this SubConn. | ||
101 | Connect() | ||
102 | } | ||
103 | |||
104 | // NewSubConnOptions contains options to create new SubConn. | ||
105 | type NewSubConnOptions struct { | ||
106 | // CredsBundle is the credentials bundle that will be used in the created | ||
107 | // SubConn. If it's nil, the original creds from grpc DialOptions will be | ||
108 | // used. | ||
109 | CredsBundle credentials.Bundle | ||
110 | // HealthCheckEnabled indicates whether health check service should be | ||
111 | // enabled on this SubConn | ||
112 | HealthCheckEnabled bool | ||
113 | } | ||
114 | |||
115 | // ClientConn represents a gRPC ClientConn. | ||
116 | // | ||
117 | // This interface is to be implemented by gRPC. Users should not need a | ||
118 | // brand new implementation of this interface. For the situations like | ||
119 | // testing, the new implementation should embed this interface. This allows | ||
120 | // gRPC to add new methods to this interface. | ||
121 | type ClientConn interface { | ||
122 | // NewSubConn is called by balancer to create a new SubConn. | ||
123 | // It doesn't block and wait for the connections to be established. | ||
124 | // Behaviors of the SubConn can be controlled by options. | ||
125 | NewSubConn([]resolver.Address, NewSubConnOptions) (SubConn, error) | ||
126 | // RemoveSubConn removes the SubConn from ClientConn. | ||
127 | // The SubConn will be shutdown. | ||
128 | RemoveSubConn(SubConn) | ||
129 | |||
130 | // UpdateBalancerState is called by balancer to nofity gRPC that some internal | ||
131 | // state in balancer has changed. | ||
132 | // | ||
133 | // gRPC will update the connectivity state of the ClientConn, and will call pick | ||
134 | // on the new picker to pick new SubConn. | ||
135 | UpdateBalancerState(s connectivity.State, p Picker) | ||
136 | |||
137 | // ResolveNow is called by balancer to notify gRPC to do a name resolving. | ||
138 | ResolveNow(resolver.ResolveNowOption) | ||
139 | |||
140 | // Target returns the dial target for this ClientConn. | ||
141 | Target() string | ||
142 | } | ||
143 | |||
144 | // BuildOptions contains additional information for Build. | ||
145 | type BuildOptions struct { | ||
146 | // DialCreds is the transport credential the Balancer implementation can | ||
147 | // use to dial to a remote load balancer server. The Balancer implementations | ||
148 | // can ignore this if it does not need to talk to another party securely. | ||
149 | DialCreds credentials.TransportCredentials | ||
150 | // CredsBundle is the credentials bundle that the Balancer can use. | ||
151 | CredsBundle credentials.Bundle | ||
152 | // Dialer is the custom dialer the Balancer implementation can use to dial | ||
153 | // to a remote load balancer server. The Balancer implementations | ||
154 | // can ignore this if it doesn't need to talk to remote balancer. | ||
155 | Dialer func(context.Context, string) (net.Conn, error) | ||
156 | // ChannelzParentID is the entity parent's channelz unique identification number. | ||
157 | ChannelzParentID int64 | ||
158 | } | ||
159 | |||
160 | // Builder creates a balancer. | ||
161 | type Builder interface { | ||
162 | // Build creates a new balancer with the ClientConn. | ||
163 | Build(cc ClientConn, opts BuildOptions) Balancer | ||
164 | // Name returns the name of balancers built by this builder. | ||
165 | // It will be used to pick balancers (for example in service config). | ||
166 | Name() string | ||
167 | } | ||
168 | |||
169 | // PickOptions contains addition information for the Pick operation. | ||
170 | type PickOptions struct { | ||
171 | // FullMethodName is the method name that NewClientStream() is called | ||
172 | // with. The canonical format is /service/Method. | ||
173 | FullMethodName string | ||
174 | // Header contains the metadata from the RPC's client header. The metadata | ||
175 | // should not be modified; make a copy first if needed. | ||
176 | Header metadata.MD | ||
177 | } | ||
178 | |||
179 | // DoneInfo contains additional information for done. | ||
180 | type DoneInfo struct { | ||
181 | // Err is the rpc error the RPC finished with. It could be nil. | ||
182 | Err error | ||
183 | // Trailer contains the metadata from the RPC's trailer, if present. | ||
184 | Trailer metadata.MD | ||
185 | // BytesSent indicates if any bytes have been sent to the server. | ||
186 | BytesSent bool | ||
187 | // BytesReceived indicates if any byte has been received from the server. | ||
188 | BytesReceived bool | ||
189 | } | ||
190 | |||
191 | var ( | ||
192 | // ErrNoSubConnAvailable indicates no SubConn is available for pick(). | ||
193 | // gRPC will block the RPC until a new picker is available via UpdateBalancerState(). | ||
194 | ErrNoSubConnAvailable = errors.New("no SubConn is available") | ||
195 | // ErrTransientFailure indicates all SubConns are in TransientFailure. | ||
196 | // WaitForReady RPCs will block, non-WaitForReady RPCs will fail. | ||
197 | ErrTransientFailure = errors.New("all SubConns are in TransientFailure") | ||
198 | ) | ||
199 | |||
200 | // Picker is used by gRPC to pick a SubConn to send an RPC. | ||
201 | // Balancer is expected to generate a new picker from its snapshot every time its | ||
202 | // internal state has changed. | ||
203 | // | ||
204 | // The pickers used by gRPC can be updated by ClientConn.UpdateBalancerState(). | ||
205 | type Picker interface { | ||
206 | // Pick returns the SubConn to be used to send the RPC. | ||
207 | // The returned SubConn must be one returned by NewSubConn(). | ||
208 | // | ||
209 | // This functions is expected to return: | ||
210 | // - a SubConn that is known to be READY; | ||
211 | // - ErrNoSubConnAvailable if no SubConn is available, but progress is being | ||
212 | // made (for example, some SubConn is in CONNECTING mode); | ||
213 | // - other errors if no active connecting is happening (for example, all SubConn | ||
214 | // are in TRANSIENT_FAILURE mode). | ||
215 | // | ||
216 | // If a SubConn is returned: | ||
217 | // - If it is READY, gRPC will send the RPC on it; | ||
218 | // - If it is not ready, or becomes not ready after it's returned, gRPC will block | ||
219 | // until UpdateBalancerState() is called and will call pick on the new picker. | ||
220 | // | ||
221 | // If the returned error is not nil: | ||
222 | // - If the error is ErrNoSubConnAvailable, gRPC will block until UpdateBalancerState() | ||
223 | // - If the error is ErrTransientFailure: | ||
224 | // - If the RPC is wait-for-ready, gRPC will block until UpdateBalancerState() | ||
225 | // is called to pick again; | ||
226 | // - Otherwise, RPC will fail with unavailable error. | ||
227 | // - Else (error is other non-nil error): | ||
228 | // - The RPC will fail with unavailable error. | ||
229 | // | ||
230 | // The returned done() function will be called once the rpc has finished, with the | ||
231 | // final status of that RPC. | ||
232 | // done may be nil if balancer doesn't care about the RPC status. | ||
233 | Pick(ctx context.Context, opts PickOptions) (conn SubConn, done func(DoneInfo), err error) | ||
234 | } | ||
235 | |||
236 | // Balancer takes input from gRPC, manages SubConns, and collects and aggregates | ||
237 | // the connectivity states. | ||
238 | // | ||
239 | // It also generates and updates the Picker used by gRPC to pick SubConns for RPCs. | ||
240 | // | ||
241 | // HandleSubConnectionStateChange, HandleResolvedAddrs and Close are guaranteed | ||
242 | // to be called synchronously from the same goroutine. | ||
243 | // There's no guarantee on picker.Pick, it may be called anytime. | ||
244 | type Balancer interface { | ||
245 | // HandleSubConnStateChange is called by gRPC when the connectivity state | ||
246 | // of sc has changed. | ||
247 | // Balancer is expected to aggregate all the state of SubConn and report | ||
248 | // that back to gRPC. | ||
249 | // Balancer should also generate and update Pickers when its internal state has | ||
250 | // been changed by the new state. | ||
251 | HandleSubConnStateChange(sc SubConn, state connectivity.State) | ||
252 | // HandleResolvedAddrs is called by gRPC to send updated resolved addresses to | ||
253 | // balancers. | ||
254 | // Balancer can create new SubConn or remove SubConn with the addresses. | ||
255 | // An empty address slice and a non-nil error will be passed if the resolver returns | ||
256 | // non-nil error to gRPC. | ||
257 | HandleResolvedAddrs([]resolver.Address, error) | ||
258 | // Close closes the balancer. The balancer is not required to call | ||
259 | // ClientConn.RemoveSubConn for its existing SubConns. | ||
260 | Close() | ||
261 | } | ||
262 | |||
263 | // ConnectivityStateEvaluator takes the connectivity states of multiple SubConns | ||
264 | // and returns one aggregated connectivity state. | ||
265 | // | ||
266 | // It's not thread safe. | ||
267 | type ConnectivityStateEvaluator struct { | ||
268 | numReady uint64 // Number of addrConns in ready state. | ||
269 | numConnecting uint64 // Number of addrConns in connecting state. | ||
270 | numTransientFailure uint64 // Number of addrConns in transientFailure. | ||
271 | } | ||
272 | |||
273 | // RecordTransition records state change happening in subConn and based on that | ||
274 | // it evaluates what aggregated state should be. | ||
275 | // | ||
276 | // - If at least one SubConn in Ready, the aggregated state is Ready; | ||
277 | // - Else if at least one SubConn in Connecting, the aggregated state is Connecting; | ||
278 | // - Else the aggregated state is TransientFailure. | ||
279 | // | ||
280 | // Idle and Shutdown are not considered. | ||
281 | func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State { | ||
282 | // Update counters. | ||
283 | for idx, state := range []connectivity.State{oldState, newState} { | ||
284 | updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new. | ||
285 | switch state { | ||
286 | case connectivity.Ready: | ||
287 | cse.numReady += updateVal | ||
288 | case connectivity.Connecting: | ||
289 | cse.numConnecting += updateVal | ||
290 | case connectivity.TransientFailure: | ||
291 | cse.numTransientFailure += updateVal | ||
292 | } | ||
293 | } | ||
294 | |||
295 | // Evaluate. | ||
296 | if cse.numReady > 0 { | ||
297 | return connectivity.Ready | ||
298 | } | ||
299 | if cse.numConnecting > 0 { | ||
300 | return connectivity.Connecting | ||
301 | } | ||
302 | return connectivity.TransientFailure | ||
303 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go new file mode 100644 index 0000000..245785e --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package base | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | |||
24 | "google.golang.org/grpc/balancer" | ||
25 | "google.golang.org/grpc/connectivity" | ||
26 | "google.golang.org/grpc/grpclog" | ||
27 | "google.golang.org/grpc/resolver" | ||
28 | ) | ||
29 | |||
30 | type baseBuilder struct { | ||
31 | name string | ||
32 | pickerBuilder PickerBuilder | ||
33 | config Config | ||
34 | } | ||
35 | |||
36 | func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { | ||
37 | return &baseBalancer{ | ||
38 | cc: cc, | ||
39 | pickerBuilder: bb.pickerBuilder, | ||
40 | |||
41 | subConns: make(map[resolver.Address]balancer.SubConn), | ||
42 | scStates: make(map[balancer.SubConn]connectivity.State), | ||
43 | csEvltr: &balancer.ConnectivityStateEvaluator{}, | ||
44 | // Initialize picker to a picker that always return | ||
45 | // ErrNoSubConnAvailable, because when state of a SubConn changes, we | ||
46 | // may call UpdateBalancerState with this picker. | ||
47 | picker: NewErrPicker(balancer.ErrNoSubConnAvailable), | ||
48 | config: bb.config, | ||
49 | } | ||
50 | } | ||
51 | |||
52 | func (bb *baseBuilder) Name() string { | ||
53 | return bb.name | ||
54 | } | ||
55 | |||
56 | type baseBalancer struct { | ||
57 | cc balancer.ClientConn | ||
58 | pickerBuilder PickerBuilder | ||
59 | |||
60 | csEvltr *balancer.ConnectivityStateEvaluator | ||
61 | state connectivity.State | ||
62 | |||
63 | subConns map[resolver.Address]balancer.SubConn | ||
64 | scStates map[balancer.SubConn]connectivity.State | ||
65 | picker balancer.Picker | ||
66 | config Config | ||
67 | } | ||
68 | |||
69 | func (b *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) { | ||
70 | if err != nil { | ||
71 | grpclog.Infof("base.baseBalancer: HandleResolvedAddrs called with error %v", err) | ||
72 | return | ||
73 | } | ||
74 | grpclog.Infoln("base.baseBalancer: got new resolved addresses: ", addrs) | ||
75 | // addrsSet is the set converted from addrs, it's used for quick lookup of an address. | ||
76 | addrsSet := make(map[resolver.Address]struct{}) | ||
77 | for _, a := range addrs { | ||
78 | addrsSet[a] = struct{}{} | ||
79 | if _, ok := b.subConns[a]; !ok { | ||
80 | // a is a new address (not existing in b.subConns). | ||
81 | sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{HealthCheckEnabled: b.config.HealthCheck}) | ||
82 | if err != nil { | ||
83 | grpclog.Warningf("base.baseBalancer: failed to create new SubConn: %v", err) | ||
84 | continue | ||
85 | } | ||
86 | b.subConns[a] = sc | ||
87 | b.scStates[sc] = connectivity.Idle | ||
88 | sc.Connect() | ||
89 | } | ||
90 | } | ||
91 | for a, sc := range b.subConns { | ||
92 | // a was removed by resolver. | ||
93 | if _, ok := addrsSet[a]; !ok { | ||
94 | b.cc.RemoveSubConn(sc) | ||
95 | delete(b.subConns, a) | ||
96 | // Keep the state of this sc in b.scStates until sc's state becomes Shutdown. | ||
97 | // The entry will be deleted in HandleSubConnStateChange. | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // regeneratePicker takes a snapshot of the balancer, and generates a picker | ||
103 | // from it. The picker is | ||
104 | // - errPicker with ErrTransientFailure if the balancer is in TransientFailure, | ||
105 | // - built by the pickerBuilder with all READY SubConns otherwise. | ||
106 | func (b *baseBalancer) regeneratePicker() { | ||
107 | if b.state == connectivity.TransientFailure { | ||
108 | b.picker = NewErrPicker(balancer.ErrTransientFailure) | ||
109 | return | ||
110 | } | ||
111 | readySCs := make(map[resolver.Address]balancer.SubConn) | ||
112 | |||
113 | // Filter out all ready SCs from full subConn map. | ||
114 | for addr, sc := range b.subConns { | ||
115 | if st, ok := b.scStates[sc]; ok && st == connectivity.Ready { | ||
116 | readySCs[addr] = sc | ||
117 | } | ||
118 | } | ||
119 | b.picker = b.pickerBuilder.Build(readySCs) | ||
120 | } | ||
121 | |||
122 | func (b *baseBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { | ||
123 | grpclog.Infof("base.baseBalancer: handle SubConn state change: %p, %v", sc, s) | ||
124 | oldS, ok := b.scStates[sc] | ||
125 | if !ok { | ||
126 | grpclog.Infof("base.baseBalancer: got state changes for an unknown SubConn: %p, %v", sc, s) | ||
127 | return | ||
128 | } | ||
129 | b.scStates[sc] = s | ||
130 | switch s { | ||
131 | case connectivity.Idle: | ||
132 | sc.Connect() | ||
133 | case connectivity.Shutdown: | ||
134 | // When an address was removed by resolver, b called RemoveSubConn but | ||
135 | // kept the sc's state in scStates. Remove state for this sc here. | ||
136 | delete(b.scStates, sc) | ||
137 | } | ||
138 | |||
139 | oldAggrState := b.state | ||
140 | b.state = b.csEvltr.RecordTransition(oldS, s) | ||
141 | |||
142 | // Regenerate picker when one of the following happens: | ||
143 | // - this sc became ready from not-ready | ||
144 | // - this sc became not-ready from ready | ||
145 | // - the aggregated state of balancer became TransientFailure from non-TransientFailure | ||
146 | // - the aggregated state of balancer became non-TransientFailure from TransientFailure | ||
147 | if (s == connectivity.Ready) != (oldS == connectivity.Ready) || | ||
148 | (b.state == connectivity.TransientFailure) != (oldAggrState == connectivity.TransientFailure) { | ||
149 | b.regeneratePicker() | ||
150 | } | ||
151 | |||
152 | b.cc.UpdateBalancerState(b.state, b.picker) | ||
153 | } | ||
154 | |||
155 | // Close is a nop because base balancer doesn't have internal state to clean up, | ||
156 | // and it doesn't need to call RemoveSubConn for the SubConns. | ||
157 | func (b *baseBalancer) Close() { | ||
158 | } | ||
159 | |||
160 | // NewErrPicker returns a picker that always returns err on Pick(). | ||
161 | func NewErrPicker(err error) balancer.Picker { | ||
162 | return &errPicker{err: err} | ||
163 | } | ||
164 | |||
165 | type errPicker struct { | ||
166 | err error // Pick() always returns this err. | ||
167 | } | ||
168 | |||
169 | func (p *errPicker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) { | ||
170 | return nil, nil, p.err | ||
171 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer/base/base.go b/vendor/google.golang.org/grpc/balancer/base/base.go new file mode 100644 index 0000000..34b1f29 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/base/base.go | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package base defines a balancer base that can be used to build balancers with | ||
20 | // different picking algorithms. | ||
21 | // | ||
22 | // The base balancer creates a new SubConn for each resolved address. The | ||
23 | // provided picker will only be notified about READY SubConns. | ||
24 | // | ||
25 | // This package is the base of round_robin balancer, its purpose is to be used | ||
26 | // to build round_robin like balancers with complex picking algorithms. | ||
27 | // Balancers with more complicated logic should try to implement a balancer | ||
28 | // builder from scratch. | ||
29 | // | ||
30 | // All APIs in this package are experimental. | ||
31 | package base | ||
32 | |||
33 | import ( | ||
34 | "google.golang.org/grpc/balancer" | ||
35 | "google.golang.org/grpc/resolver" | ||
36 | ) | ||
37 | |||
38 | // PickerBuilder creates balancer.Picker. | ||
39 | type PickerBuilder interface { | ||
40 | // Build takes a slice of ready SubConns, and returns a picker that will be | ||
41 | // used by gRPC to pick a SubConn. | ||
42 | Build(readySCs map[resolver.Address]balancer.SubConn) balancer.Picker | ||
43 | } | ||
44 | |||
45 | // NewBalancerBuilder returns a balancer builder. The balancers | ||
46 | // built by this builder will use the picker builder to build pickers. | ||
47 | func NewBalancerBuilder(name string, pb PickerBuilder) balancer.Builder { | ||
48 | return NewBalancerBuilderWithConfig(name, pb, Config{}) | ||
49 | } | ||
50 | |||
51 | // Config contains the config info about the base balancer builder. | ||
52 | type Config struct { | ||
53 | // HealthCheck indicates whether health checking should be enabled for this specific balancer. | ||
54 | HealthCheck bool | ||
55 | } | ||
56 | |||
57 | // NewBalancerBuilderWithConfig returns a base balancer builder configured by the provided config. | ||
58 | func NewBalancerBuilderWithConfig(name string, pb PickerBuilder, config Config) balancer.Builder { | ||
59 | return &baseBuilder{ | ||
60 | name: name, | ||
61 | pickerBuilder: pb, | ||
62 | config: config, | ||
63 | } | ||
64 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go new file mode 100644 index 0000000..57aea9f --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package roundrobin defines a roundrobin balancer. Roundrobin balancer is | ||
20 | // installed as one of the default balancers in gRPC, users don't need to | ||
21 | // explicitly install this balancer. | ||
22 | package roundrobin | ||
23 | |||
24 | import ( | ||
25 | "context" | ||
26 | "sync" | ||
27 | |||
28 | "google.golang.org/grpc/balancer" | ||
29 | "google.golang.org/grpc/balancer/base" | ||
30 | "google.golang.org/grpc/grpclog" | ||
31 | "google.golang.org/grpc/resolver" | ||
32 | ) | ||
33 | |||
34 | // Name is the name of round_robin balancer. | ||
35 | const Name = "round_robin" | ||
36 | |||
37 | // newBuilder creates a new roundrobin balancer builder. | ||
38 | func newBuilder() balancer.Builder { | ||
39 | return base.NewBalancerBuilderWithConfig(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true}) | ||
40 | } | ||
41 | |||
42 | func init() { | ||
43 | balancer.Register(newBuilder()) | ||
44 | } | ||
45 | |||
46 | type rrPickerBuilder struct{} | ||
47 | |||
48 | func (*rrPickerBuilder) Build(readySCs map[resolver.Address]balancer.SubConn) balancer.Picker { | ||
49 | grpclog.Infof("roundrobinPicker: newPicker called with readySCs: %v", readySCs) | ||
50 | var scs []balancer.SubConn | ||
51 | for _, sc := range readySCs { | ||
52 | scs = append(scs, sc) | ||
53 | } | ||
54 | return &rrPicker{ | ||
55 | subConns: scs, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | type rrPicker struct { | ||
60 | // subConns is the snapshot of the roundrobin balancer when this picker was | ||
61 | // created. The slice is immutable. Each Get() will do a round robin | ||
62 | // selection from it and return the selected SubConn. | ||
63 | subConns []balancer.SubConn | ||
64 | |||
65 | mu sync.Mutex | ||
66 | next int | ||
67 | } | ||
68 | |||
69 | func (p *rrPicker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) { | ||
70 | if len(p.subConns) <= 0 { | ||
71 | return nil, nil, balancer.ErrNoSubConnAvailable | ||
72 | } | ||
73 | |||
74 | p.mu.Lock() | ||
75 | sc := p.subConns[p.next] | ||
76 | p.next = (p.next + 1) % len(p.subConns) | ||
77 | p.mu.Unlock() | ||
78 | return sc, nil, nil | ||
79 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go new file mode 100644 index 0000000..7233ade --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "fmt" | ||
23 | "sync" | ||
24 | |||
25 | "google.golang.org/grpc/balancer" | ||
26 | "google.golang.org/grpc/connectivity" | ||
27 | "google.golang.org/grpc/grpclog" | ||
28 | "google.golang.org/grpc/resolver" | ||
29 | ) | ||
30 | |||
31 | // scStateUpdate contains the subConn and the new state it changed to. | ||
32 | type scStateUpdate struct { | ||
33 | sc balancer.SubConn | ||
34 | state connectivity.State | ||
35 | } | ||
36 | |||
37 | // scStateUpdateBuffer is an unbounded channel for scStateChangeTuple. | ||
38 | // TODO make a general purpose buffer that uses interface{}. | ||
39 | type scStateUpdateBuffer struct { | ||
40 | c chan *scStateUpdate | ||
41 | mu sync.Mutex | ||
42 | backlog []*scStateUpdate | ||
43 | } | ||
44 | |||
45 | func newSCStateUpdateBuffer() *scStateUpdateBuffer { | ||
46 | return &scStateUpdateBuffer{ | ||
47 | c: make(chan *scStateUpdate, 1), | ||
48 | } | ||
49 | } | ||
50 | |||
51 | func (b *scStateUpdateBuffer) put(t *scStateUpdate) { | ||
52 | b.mu.Lock() | ||
53 | defer b.mu.Unlock() | ||
54 | if len(b.backlog) == 0 { | ||
55 | select { | ||
56 | case b.c <- t: | ||
57 | return | ||
58 | default: | ||
59 | } | ||
60 | } | ||
61 | b.backlog = append(b.backlog, t) | ||
62 | } | ||
63 | |||
64 | func (b *scStateUpdateBuffer) load() { | ||
65 | b.mu.Lock() | ||
66 | defer b.mu.Unlock() | ||
67 | if len(b.backlog) > 0 { | ||
68 | select { | ||
69 | case b.c <- b.backlog[0]: | ||
70 | b.backlog[0] = nil | ||
71 | b.backlog = b.backlog[1:] | ||
72 | default: | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // get returns the channel that the scStateUpdate will be sent to. | ||
78 | // | ||
79 | // Upon receiving, the caller should call load to send another | ||
80 | // scStateChangeTuple onto the channel if there is any. | ||
81 | func (b *scStateUpdateBuffer) get() <-chan *scStateUpdate { | ||
82 | return b.c | ||
83 | } | ||
84 | |||
85 | // resolverUpdate contains the new resolved addresses or error if there's | ||
86 | // any. | ||
87 | type resolverUpdate struct { | ||
88 | addrs []resolver.Address | ||
89 | err error | ||
90 | } | ||
91 | |||
92 | // ccBalancerWrapper is a wrapper on top of cc for balancers. | ||
93 | // It implements balancer.ClientConn interface. | ||
94 | type ccBalancerWrapper struct { | ||
95 | cc *ClientConn | ||
96 | balancer balancer.Balancer | ||
97 | stateChangeQueue *scStateUpdateBuffer | ||
98 | resolverUpdateCh chan *resolverUpdate | ||
99 | done chan struct{} | ||
100 | |||
101 | mu sync.Mutex | ||
102 | subConns map[*acBalancerWrapper]struct{} | ||
103 | } | ||
104 | |||
105 | func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.BuildOptions) *ccBalancerWrapper { | ||
106 | ccb := &ccBalancerWrapper{ | ||
107 | cc: cc, | ||
108 | stateChangeQueue: newSCStateUpdateBuffer(), | ||
109 | resolverUpdateCh: make(chan *resolverUpdate, 1), | ||
110 | done: make(chan struct{}), | ||
111 | subConns: make(map[*acBalancerWrapper]struct{}), | ||
112 | } | ||
113 | go ccb.watcher() | ||
114 | ccb.balancer = b.Build(ccb, bopts) | ||
115 | return ccb | ||
116 | } | ||
117 | |||
118 | // watcher balancer functions sequentially, so the balancer can be implemented | ||
119 | // lock-free. | ||
120 | func (ccb *ccBalancerWrapper) watcher() { | ||
121 | for { | ||
122 | select { | ||
123 | case t := <-ccb.stateChangeQueue.get(): | ||
124 | ccb.stateChangeQueue.load() | ||
125 | select { | ||
126 | case <-ccb.done: | ||
127 | ccb.balancer.Close() | ||
128 | return | ||
129 | default: | ||
130 | } | ||
131 | ccb.balancer.HandleSubConnStateChange(t.sc, t.state) | ||
132 | case t := <-ccb.resolverUpdateCh: | ||
133 | select { | ||
134 | case <-ccb.done: | ||
135 | ccb.balancer.Close() | ||
136 | return | ||
137 | default: | ||
138 | } | ||
139 | ccb.balancer.HandleResolvedAddrs(t.addrs, t.err) | ||
140 | case <-ccb.done: | ||
141 | } | ||
142 | |||
143 | select { | ||
144 | case <-ccb.done: | ||
145 | ccb.balancer.Close() | ||
146 | ccb.mu.Lock() | ||
147 | scs := ccb.subConns | ||
148 | ccb.subConns = nil | ||
149 | ccb.mu.Unlock() | ||
150 | for acbw := range scs { | ||
151 | ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain) | ||
152 | } | ||
153 | return | ||
154 | default: | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | func (ccb *ccBalancerWrapper) close() { | ||
160 | close(ccb.done) | ||
161 | } | ||
162 | |||
163 | func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { | ||
164 | // When updating addresses for a SubConn, if the address in use is not in | ||
165 | // the new addresses, the old ac will be tearDown() and a new ac will be | ||
166 | // created. tearDown() generates a state change with Shutdown state, we | ||
167 | // don't want the balancer to receive this state change. So before | ||
168 | // tearDown() on the old ac, ac.acbw (acWrapper) will be set to nil, and | ||
169 | // this function will be called with (nil, Shutdown). We don't need to call | ||
170 | // balancer method in this case. | ||
171 | if sc == nil { | ||
172 | return | ||
173 | } | ||
174 | ccb.stateChangeQueue.put(&scStateUpdate{ | ||
175 | sc: sc, | ||
176 | state: s, | ||
177 | }) | ||
178 | } | ||
179 | |||
180 | func (ccb *ccBalancerWrapper) handleResolvedAddrs(addrs []resolver.Address, err error) { | ||
181 | if ccb.cc.curBalancerName != grpclbName { | ||
182 | var containsGRPCLB bool | ||
183 | for _, a := range addrs { | ||
184 | if a.Type == resolver.GRPCLB { | ||
185 | containsGRPCLB = true | ||
186 | break | ||
187 | } | ||
188 | } | ||
189 | if containsGRPCLB { | ||
190 | // The current balancer is not grpclb, but addresses contain grpclb | ||
191 | // address. This means we failed to switch to grpclb, most likely | ||
192 | // because grpclb is not registered. Filter out all grpclb addresses | ||
193 | // from addrs before sending to balancer. | ||
194 | tempAddrs := make([]resolver.Address, 0, len(addrs)) | ||
195 | for _, a := range addrs { | ||
196 | if a.Type != resolver.GRPCLB { | ||
197 | tempAddrs = append(tempAddrs, a) | ||
198 | } | ||
199 | } | ||
200 | addrs = tempAddrs | ||
201 | } | ||
202 | } | ||
203 | select { | ||
204 | case <-ccb.resolverUpdateCh: | ||
205 | default: | ||
206 | } | ||
207 | ccb.resolverUpdateCh <- &resolverUpdate{ | ||
208 | addrs: addrs, | ||
209 | err: err, | ||
210 | } | ||
211 | } | ||
212 | |||
213 | func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { | ||
214 | if len(addrs) <= 0 { | ||
215 | return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list") | ||
216 | } | ||
217 | ccb.mu.Lock() | ||
218 | defer ccb.mu.Unlock() | ||
219 | if ccb.subConns == nil { | ||
220 | return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed") | ||
221 | } | ||
222 | ac, err := ccb.cc.newAddrConn(addrs, opts) | ||
223 | if err != nil { | ||
224 | return nil, err | ||
225 | } | ||
226 | acbw := &acBalancerWrapper{ac: ac} | ||
227 | acbw.ac.mu.Lock() | ||
228 | ac.acbw = acbw | ||
229 | acbw.ac.mu.Unlock() | ||
230 | ccb.subConns[acbw] = struct{}{} | ||
231 | return acbw, nil | ||
232 | } | ||
233 | |||
234 | func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) { | ||
235 | acbw, ok := sc.(*acBalancerWrapper) | ||
236 | if !ok { | ||
237 | return | ||
238 | } | ||
239 | ccb.mu.Lock() | ||
240 | defer ccb.mu.Unlock() | ||
241 | if ccb.subConns == nil { | ||
242 | return | ||
243 | } | ||
244 | delete(ccb.subConns, acbw) | ||
245 | ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain) | ||
246 | } | ||
247 | |||
248 | func (ccb *ccBalancerWrapper) UpdateBalancerState(s connectivity.State, p balancer.Picker) { | ||
249 | ccb.mu.Lock() | ||
250 | defer ccb.mu.Unlock() | ||
251 | if ccb.subConns == nil { | ||
252 | return | ||
253 | } | ||
254 | // Update picker before updating state. Even though the ordering here does | ||
255 | // not matter, it can lead to multiple calls of Pick in the common start-up | ||
256 | // case where we wait for ready and then perform an RPC. If the picker is | ||
257 | // updated later, we could call the "connecting" picker when the state is | ||
258 | // updated, and then call the "ready" picker after the picker gets updated. | ||
259 | ccb.cc.blockingpicker.updatePicker(p) | ||
260 | ccb.cc.csMgr.updateState(s) | ||
261 | } | ||
262 | |||
263 | func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOption) { | ||
264 | ccb.cc.resolveNow(o) | ||
265 | } | ||
266 | |||
267 | func (ccb *ccBalancerWrapper) Target() string { | ||
268 | return ccb.cc.target | ||
269 | } | ||
270 | |||
271 | // acBalancerWrapper is a wrapper on top of ac for balancers. | ||
272 | // It implements balancer.SubConn interface. | ||
273 | type acBalancerWrapper struct { | ||
274 | mu sync.Mutex | ||
275 | ac *addrConn | ||
276 | } | ||
277 | |||
278 | func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { | ||
279 | acbw.mu.Lock() | ||
280 | defer acbw.mu.Unlock() | ||
281 | if len(addrs) <= 0 { | ||
282 | acbw.ac.tearDown(errConnDrain) | ||
283 | return | ||
284 | } | ||
285 | if !acbw.ac.tryUpdateAddrs(addrs) { | ||
286 | cc := acbw.ac.cc | ||
287 | opts := acbw.ac.scopts | ||
288 | acbw.ac.mu.Lock() | ||
289 | // Set old ac.acbw to nil so the Shutdown state update will be ignored | ||
290 | // by balancer. | ||
291 | // | ||
292 | // TODO(bar) the state transition could be wrong when tearDown() old ac | ||
293 | // and creating new ac, fix the transition. | ||
294 | acbw.ac.acbw = nil | ||
295 | acbw.ac.mu.Unlock() | ||
296 | acState := acbw.ac.getState() | ||
297 | acbw.ac.tearDown(errConnDrain) | ||
298 | |||
299 | if acState == connectivity.Shutdown { | ||
300 | return | ||
301 | } | ||
302 | |||
303 | ac, err := cc.newAddrConn(addrs, opts) | ||
304 | if err != nil { | ||
305 | grpclog.Warningf("acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err) | ||
306 | return | ||
307 | } | ||
308 | acbw.ac = ac | ||
309 | ac.mu.Lock() | ||
310 | ac.acbw = acbw | ||
311 | ac.mu.Unlock() | ||
312 | if acState != connectivity.Idle { | ||
313 | ac.connect() | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | func (acbw *acBalancerWrapper) Connect() { | ||
319 | acbw.mu.Lock() | ||
320 | defer acbw.mu.Unlock() | ||
321 | acbw.ac.connect() | ||
322 | } | ||
323 | |||
324 | func (acbw *acBalancerWrapper) getAddrConn() *addrConn { | ||
325 | acbw.mu.Lock() | ||
326 | defer acbw.mu.Unlock() | ||
327 | return acbw.ac | ||
328 | } | ||
diff --git a/vendor/google.golang.org/grpc/balancer_v1_wrapper.go b/vendor/google.golang.org/grpc/balancer_v1_wrapper.go new file mode 100644 index 0000000..42b60fe --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer_v1_wrapper.go | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | "strings" | ||
24 | "sync" | ||
25 | |||
26 | "google.golang.org/grpc/balancer" | ||
27 | "google.golang.org/grpc/connectivity" | ||
28 | "google.golang.org/grpc/grpclog" | ||
29 | "google.golang.org/grpc/resolver" | ||
30 | ) | ||
31 | |||
32 | type balancerWrapperBuilder struct { | ||
33 | b Balancer // The v1 balancer. | ||
34 | } | ||
35 | |||
36 | func (bwb *balancerWrapperBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { | ||
37 | targetAddr := cc.Target() | ||
38 | targetSplitted := strings.Split(targetAddr, ":///") | ||
39 | if len(targetSplitted) >= 2 { | ||
40 | targetAddr = targetSplitted[1] | ||
41 | } | ||
42 | |||
43 | bwb.b.Start(targetAddr, BalancerConfig{ | ||
44 | DialCreds: opts.DialCreds, | ||
45 | Dialer: opts.Dialer, | ||
46 | }) | ||
47 | _, pickfirst := bwb.b.(*pickFirst) | ||
48 | bw := &balancerWrapper{ | ||
49 | balancer: bwb.b, | ||
50 | pickfirst: pickfirst, | ||
51 | cc: cc, | ||
52 | targetAddr: targetAddr, | ||
53 | startCh: make(chan struct{}), | ||
54 | conns: make(map[resolver.Address]balancer.SubConn), | ||
55 | connSt: make(map[balancer.SubConn]*scState), | ||
56 | csEvltr: &balancer.ConnectivityStateEvaluator{}, | ||
57 | state: connectivity.Idle, | ||
58 | } | ||
59 | cc.UpdateBalancerState(connectivity.Idle, bw) | ||
60 | go bw.lbWatcher() | ||
61 | return bw | ||
62 | } | ||
63 | |||
64 | func (bwb *balancerWrapperBuilder) Name() string { | ||
65 | return "wrapper" | ||
66 | } | ||
67 | |||
68 | type scState struct { | ||
69 | addr Address // The v1 address type. | ||
70 | s connectivity.State | ||
71 | down func(error) | ||
72 | } | ||
73 | |||
74 | type balancerWrapper struct { | ||
75 | balancer Balancer // The v1 balancer. | ||
76 | pickfirst bool | ||
77 | |||
78 | cc balancer.ClientConn | ||
79 | targetAddr string // Target without the scheme. | ||
80 | |||
81 | mu sync.Mutex | ||
82 | conns map[resolver.Address]balancer.SubConn | ||
83 | connSt map[balancer.SubConn]*scState | ||
84 | // This channel is closed when handling the first resolver result. | ||
85 | // lbWatcher blocks until this is closed, to avoid race between | ||
86 | // - NewSubConn is created, cc wants to notify balancer of state changes; | ||
87 | // - Build hasn't return, cc doesn't have access to balancer. | ||
88 | startCh chan struct{} | ||
89 | |||
90 | // To aggregate the connectivity state. | ||
91 | csEvltr *balancer.ConnectivityStateEvaluator | ||
92 | state connectivity.State | ||
93 | } | ||
94 | |||
95 | // lbWatcher watches the Notify channel of the balancer and manages | ||
96 | // connections accordingly. | ||
97 | func (bw *balancerWrapper) lbWatcher() { | ||
98 | <-bw.startCh | ||
99 | notifyCh := bw.balancer.Notify() | ||
100 | if notifyCh == nil { | ||
101 | // There's no resolver in the balancer. Connect directly. | ||
102 | a := resolver.Address{ | ||
103 | Addr: bw.targetAddr, | ||
104 | Type: resolver.Backend, | ||
105 | } | ||
106 | sc, err := bw.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{}) | ||
107 | if err != nil { | ||
108 | grpclog.Warningf("Error creating connection to %v. Err: %v", a, err) | ||
109 | } else { | ||
110 | bw.mu.Lock() | ||
111 | bw.conns[a] = sc | ||
112 | bw.connSt[sc] = &scState{ | ||
113 | addr: Address{Addr: bw.targetAddr}, | ||
114 | s: connectivity.Idle, | ||
115 | } | ||
116 | bw.mu.Unlock() | ||
117 | sc.Connect() | ||
118 | } | ||
119 | return | ||
120 | } | ||
121 | |||
122 | for addrs := range notifyCh { | ||
123 | grpclog.Infof("balancerWrapper: got update addr from Notify: %v\n", addrs) | ||
124 | if bw.pickfirst { | ||
125 | var ( | ||
126 | oldA resolver.Address | ||
127 | oldSC balancer.SubConn | ||
128 | ) | ||
129 | bw.mu.Lock() | ||
130 | for oldA, oldSC = range bw.conns { | ||
131 | break | ||
132 | } | ||
133 | bw.mu.Unlock() | ||
134 | if len(addrs) <= 0 { | ||
135 | if oldSC != nil { | ||
136 | // Teardown old sc. | ||
137 | bw.mu.Lock() | ||
138 | delete(bw.conns, oldA) | ||
139 | delete(bw.connSt, oldSC) | ||
140 | bw.mu.Unlock() | ||
141 | bw.cc.RemoveSubConn(oldSC) | ||
142 | } | ||
143 | continue | ||
144 | } | ||
145 | |||
146 | var newAddrs []resolver.Address | ||
147 | for _, a := range addrs { | ||
148 | newAddr := resolver.Address{ | ||
149 | Addr: a.Addr, | ||
150 | Type: resolver.Backend, // All addresses from balancer are all backends. | ||
151 | ServerName: "", | ||
152 | Metadata: a.Metadata, | ||
153 | } | ||
154 | newAddrs = append(newAddrs, newAddr) | ||
155 | } | ||
156 | if oldSC == nil { | ||
157 | // Create new sc. | ||
158 | sc, err := bw.cc.NewSubConn(newAddrs, balancer.NewSubConnOptions{}) | ||
159 | if err != nil { | ||
160 | grpclog.Warningf("Error creating connection to %v. Err: %v", newAddrs, err) | ||
161 | } else { | ||
162 | bw.mu.Lock() | ||
163 | // For pickfirst, there should be only one SubConn, so the | ||
164 | // address doesn't matter. All states updating (up and down) | ||
165 | // and picking should all happen on that only SubConn. | ||
166 | bw.conns[resolver.Address{}] = sc | ||
167 | bw.connSt[sc] = &scState{ | ||
168 | addr: addrs[0], // Use the first address. | ||
169 | s: connectivity.Idle, | ||
170 | } | ||
171 | bw.mu.Unlock() | ||
172 | sc.Connect() | ||
173 | } | ||
174 | } else { | ||
175 | bw.mu.Lock() | ||
176 | bw.connSt[oldSC].addr = addrs[0] | ||
177 | bw.mu.Unlock() | ||
178 | oldSC.UpdateAddresses(newAddrs) | ||
179 | } | ||
180 | } else { | ||
181 | var ( | ||
182 | add []resolver.Address // Addresses need to setup connections. | ||
183 | del []balancer.SubConn // Connections need to tear down. | ||
184 | ) | ||
185 | resAddrs := make(map[resolver.Address]Address) | ||
186 | for _, a := range addrs { | ||
187 | resAddrs[resolver.Address{ | ||
188 | Addr: a.Addr, | ||
189 | Type: resolver.Backend, // All addresses from balancer are all backends. | ||
190 | ServerName: "", | ||
191 | Metadata: a.Metadata, | ||
192 | }] = a | ||
193 | } | ||
194 | bw.mu.Lock() | ||
195 | for a := range resAddrs { | ||
196 | if _, ok := bw.conns[a]; !ok { | ||
197 | add = append(add, a) | ||
198 | } | ||
199 | } | ||
200 | for a, c := range bw.conns { | ||
201 | if _, ok := resAddrs[a]; !ok { | ||
202 | del = append(del, c) | ||
203 | delete(bw.conns, a) | ||
204 | // Keep the state of this sc in bw.connSt until its state becomes Shutdown. | ||
205 | } | ||
206 | } | ||
207 | bw.mu.Unlock() | ||
208 | for _, a := range add { | ||
209 | sc, err := bw.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{}) | ||
210 | if err != nil { | ||
211 | grpclog.Warningf("Error creating connection to %v. Err: %v", a, err) | ||
212 | } else { | ||
213 | bw.mu.Lock() | ||
214 | bw.conns[a] = sc | ||
215 | bw.connSt[sc] = &scState{ | ||
216 | addr: resAddrs[a], | ||
217 | s: connectivity.Idle, | ||
218 | } | ||
219 | bw.mu.Unlock() | ||
220 | sc.Connect() | ||
221 | } | ||
222 | } | ||
223 | for _, c := range del { | ||
224 | bw.cc.RemoveSubConn(c) | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | func (bw *balancerWrapper) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { | ||
231 | bw.mu.Lock() | ||
232 | defer bw.mu.Unlock() | ||
233 | scSt, ok := bw.connSt[sc] | ||
234 | if !ok { | ||
235 | return | ||
236 | } | ||
237 | if s == connectivity.Idle { | ||
238 | sc.Connect() | ||
239 | } | ||
240 | oldS := scSt.s | ||
241 | scSt.s = s | ||
242 | if oldS != connectivity.Ready && s == connectivity.Ready { | ||
243 | scSt.down = bw.balancer.Up(scSt.addr) | ||
244 | } else if oldS == connectivity.Ready && s != connectivity.Ready { | ||
245 | if scSt.down != nil { | ||
246 | scSt.down(errConnClosing) | ||
247 | } | ||
248 | } | ||
249 | sa := bw.csEvltr.RecordTransition(oldS, s) | ||
250 | if bw.state != sa { | ||
251 | bw.state = sa | ||
252 | } | ||
253 | bw.cc.UpdateBalancerState(bw.state, bw) | ||
254 | if s == connectivity.Shutdown { | ||
255 | // Remove state for this sc. | ||
256 | delete(bw.connSt, sc) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | func (bw *balancerWrapper) HandleResolvedAddrs([]resolver.Address, error) { | ||
261 | bw.mu.Lock() | ||
262 | defer bw.mu.Unlock() | ||
263 | select { | ||
264 | case <-bw.startCh: | ||
265 | default: | ||
266 | close(bw.startCh) | ||
267 | } | ||
268 | // There should be a resolver inside the balancer. | ||
269 | // All updates here, if any, are ignored. | ||
270 | } | ||
271 | |||
272 | func (bw *balancerWrapper) Close() { | ||
273 | bw.mu.Lock() | ||
274 | defer bw.mu.Unlock() | ||
275 | select { | ||
276 | case <-bw.startCh: | ||
277 | default: | ||
278 | close(bw.startCh) | ||
279 | } | ||
280 | bw.balancer.Close() | ||
281 | } | ||
282 | |||
283 | // The picker is the balancerWrapper itself. | ||
284 | // Pick should never return ErrNoSubConnAvailable. | ||
285 | // It either blocks or returns error, consistent with v1 balancer Get(). | ||
286 | func (bw *balancerWrapper) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) { | ||
287 | failfast := true // Default failfast is true. | ||
288 | if ss, ok := rpcInfoFromContext(ctx); ok { | ||
289 | failfast = ss.failfast | ||
290 | } | ||
291 | a, p, err := bw.balancer.Get(ctx, BalancerGetOptions{BlockingWait: !failfast}) | ||
292 | if err != nil { | ||
293 | return nil, nil, err | ||
294 | } | ||
295 | var done func(balancer.DoneInfo) | ||
296 | if p != nil { | ||
297 | done = func(i balancer.DoneInfo) { p() } | ||
298 | } | ||
299 | var sc balancer.SubConn | ||
300 | bw.mu.Lock() | ||
301 | defer bw.mu.Unlock() | ||
302 | if bw.pickfirst { | ||
303 | // Get the first sc in conns. | ||
304 | for _, sc = range bw.conns { | ||
305 | break | ||
306 | } | ||
307 | } else { | ||
308 | var ok bool | ||
309 | sc, ok = bw.conns[resolver.Address{ | ||
310 | Addr: a.Addr, | ||
311 | Type: resolver.Backend, | ||
312 | ServerName: "", | ||
313 | Metadata: a.Metadata, | ||
314 | }] | ||
315 | if !ok && failfast { | ||
316 | return nil, nil, balancer.ErrTransientFailure | ||
317 | } | ||
318 | if s, ok := bw.connSt[sc]; failfast && (!ok || s.s != connectivity.Ready) { | ||
319 | // If the returned sc is not ready and RPC is failfast, | ||
320 | // return error, and this RPC will fail. | ||
321 | return nil, nil, balancer.ErrTransientFailure | ||
322 | } | ||
323 | } | ||
324 | |||
325 | return sc, done, nil | ||
326 | } | ||
diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go new file mode 100644 index 0000000..f393bb6 --- /dev/null +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go | |||
@@ -0,0 +1,900 @@ | |||
1 | // Code generated by protoc-gen-go. DO NOT EDIT. | ||
2 | // source: grpc/binarylog/grpc_binarylog_v1/binarylog.proto | ||
3 | |||
4 | package grpc_binarylog_v1 // import "google.golang.org/grpc/binarylog/grpc_binarylog_v1" | ||
5 | |||
6 | import proto "github.com/golang/protobuf/proto" | ||
7 | import fmt "fmt" | ||
8 | import math "math" | ||
9 | import duration "github.com/golang/protobuf/ptypes/duration" | ||
10 | import timestamp "github.com/golang/protobuf/ptypes/timestamp" | ||
11 | |||
12 | // Reference imports to suppress errors if they are not otherwise used. | ||
13 | var _ = proto.Marshal | ||
14 | var _ = fmt.Errorf | ||
15 | var _ = math.Inf | ||
16 | |||
17 | // This is a compile-time assertion to ensure that this generated file | ||
18 | // is compatible with the proto package it is being compiled against. | ||
19 | // A compilation error at this line likely means your copy of the | ||
20 | // proto package needs to be updated. | ||
21 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||
22 | |||
23 | // Enumerates the type of event | ||
24 | // Note the terminology is different from the RPC semantics | ||
25 | // definition, but the same meaning is expressed here. | ||
26 | type GrpcLogEntry_EventType int32 | ||
27 | |||
28 | const ( | ||
29 | GrpcLogEntry_EVENT_TYPE_UNKNOWN GrpcLogEntry_EventType = 0 | ||
30 | // Header sent from client to server | ||
31 | GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER GrpcLogEntry_EventType = 1 | ||
32 | // Header sent from server to client | ||
33 | GrpcLogEntry_EVENT_TYPE_SERVER_HEADER GrpcLogEntry_EventType = 2 | ||
34 | // Message sent from client to server | ||
35 | GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE GrpcLogEntry_EventType = 3 | ||
36 | // Message sent from server to client | ||
37 | GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE GrpcLogEntry_EventType = 4 | ||
38 | // A signal that client is done sending | ||
39 | GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE GrpcLogEntry_EventType = 5 | ||
40 | // Trailer indicates the end of the RPC. | ||
41 | // On client side, this event means a trailer was either received | ||
42 | // from the network or the gRPC library locally generated a status | ||
43 | // to inform the application about a failure. | ||
44 | // On server side, this event means the server application requested | ||
45 | // to send a trailer. Note: EVENT_TYPE_CANCEL may still arrive after | ||
46 | // this due to races on server side. | ||
47 | GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER GrpcLogEntry_EventType = 6 | ||
48 | // A signal that the RPC is cancelled. On client side, this | ||
49 | // indicates the client application requests a cancellation. | ||
50 | // On server side, this indicates that cancellation was detected. | ||
51 | // Note: This marks the end of the RPC. Events may arrive after | ||
52 | // this due to races. For example, on client side a trailer | ||
53 | // may arrive even though the application requested to cancel the RPC. | ||
54 | GrpcLogEntry_EVENT_TYPE_CANCEL GrpcLogEntry_EventType = 7 | ||
55 | ) | ||
56 | |||
57 | var GrpcLogEntry_EventType_name = map[int32]string{ | ||
58 | 0: "EVENT_TYPE_UNKNOWN", | ||
59 | 1: "EVENT_TYPE_CLIENT_HEADER", | ||
60 | 2: "EVENT_TYPE_SERVER_HEADER", | ||
61 | 3: "EVENT_TYPE_CLIENT_MESSAGE", | ||
62 | 4: "EVENT_TYPE_SERVER_MESSAGE", | ||
63 | 5: "EVENT_TYPE_CLIENT_HALF_CLOSE", | ||
64 | 6: "EVENT_TYPE_SERVER_TRAILER", | ||
65 | 7: "EVENT_TYPE_CANCEL", | ||
66 | } | ||
67 | var GrpcLogEntry_EventType_value = map[string]int32{ | ||
68 | "EVENT_TYPE_UNKNOWN": 0, | ||
69 | "EVENT_TYPE_CLIENT_HEADER": 1, | ||
70 | "EVENT_TYPE_SERVER_HEADER": 2, | ||
71 | "EVENT_TYPE_CLIENT_MESSAGE": 3, | ||
72 | "EVENT_TYPE_SERVER_MESSAGE": 4, | ||
73 | "EVENT_TYPE_CLIENT_HALF_CLOSE": 5, | ||
74 | "EVENT_TYPE_SERVER_TRAILER": 6, | ||
75 | "EVENT_TYPE_CANCEL": 7, | ||
76 | } | ||
77 | |||
78 | func (x GrpcLogEntry_EventType) String() string { | ||
79 | return proto.EnumName(GrpcLogEntry_EventType_name, int32(x)) | ||
80 | } | ||
81 | func (GrpcLogEntry_EventType) EnumDescriptor() ([]byte, []int) { | ||
82 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{0, 0} | ||
83 | } | ||
84 | |||
85 | // Enumerates the entity that generates the log entry | ||
86 | type GrpcLogEntry_Logger int32 | ||
87 | |||
88 | const ( | ||
89 | GrpcLogEntry_LOGGER_UNKNOWN GrpcLogEntry_Logger = 0 | ||
90 | GrpcLogEntry_LOGGER_CLIENT GrpcLogEntry_Logger = 1 | ||
91 | GrpcLogEntry_LOGGER_SERVER GrpcLogEntry_Logger = 2 | ||
92 | ) | ||
93 | |||
94 | var GrpcLogEntry_Logger_name = map[int32]string{ | ||
95 | 0: "LOGGER_UNKNOWN", | ||
96 | 1: "LOGGER_CLIENT", | ||
97 | 2: "LOGGER_SERVER", | ||
98 | } | ||
99 | var GrpcLogEntry_Logger_value = map[string]int32{ | ||
100 | "LOGGER_UNKNOWN": 0, | ||
101 | "LOGGER_CLIENT": 1, | ||
102 | "LOGGER_SERVER": 2, | ||
103 | } | ||
104 | |||
105 | func (x GrpcLogEntry_Logger) String() string { | ||
106 | return proto.EnumName(GrpcLogEntry_Logger_name, int32(x)) | ||
107 | } | ||
108 | func (GrpcLogEntry_Logger) EnumDescriptor() ([]byte, []int) { | ||
109 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{0, 1} | ||
110 | } | ||
111 | |||
112 | type Address_Type int32 | ||
113 | |||
114 | const ( | ||
115 | Address_TYPE_UNKNOWN Address_Type = 0 | ||
116 | // address is in 1.2.3.4 form | ||
117 | Address_TYPE_IPV4 Address_Type = 1 | ||
118 | // address is in IPv6 canonical form (RFC5952 section 4) | ||
119 | // The scope is NOT included in the address string. | ||
120 | Address_TYPE_IPV6 Address_Type = 2 | ||
121 | // address is UDS string | ||
122 | Address_TYPE_UNIX Address_Type = 3 | ||
123 | ) | ||
124 | |||
125 | var Address_Type_name = map[int32]string{ | ||
126 | 0: "TYPE_UNKNOWN", | ||
127 | 1: "TYPE_IPV4", | ||
128 | 2: "TYPE_IPV6", | ||
129 | 3: "TYPE_UNIX", | ||
130 | } | ||
131 | var Address_Type_value = map[string]int32{ | ||
132 | "TYPE_UNKNOWN": 0, | ||
133 | "TYPE_IPV4": 1, | ||
134 | "TYPE_IPV6": 2, | ||
135 | "TYPE_UNIX": 3, | ||
136 | } | ||
137 | |||
138 | func (x Address_Type) String() string { | ||
139 | return proto.EnumName(Address_Type_name, int32(x)) | ||
140 | } | ||
141 | func (Address_Type) EnumDescriptor() ([]byte, []int) { | ||
142 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{7, 0} | ||
143 | } | ||
144 | |||
145 | // Log entry we store in binary logs | ||
146 | type GrpcLogEntry struct { | ||
147 | // The timestamp of the binary log message | ||
148 | Timestamp *timestamp.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` | ||
149 | // Uniquely identifies a call. The value must not be 0 in order to disambiguate | ||
150 | // from an unset value. | ||
151 | // Each call may have several log entries, they will all have the same call_id. | ||
152 | // Nothing is guaranteed about their value other than they are unique across | ||
153 | // different RPCs in the same gRPC process. | ||
154 | CallId uint64 `protobuf:"varint,2,opt,name=call_id,json=callId,proto3" json:"call_id,omitempty"` | ||
155 | // The entry sequence id for this call. The first GrpcLogEntry has a | ||
156 | // value of 1, to disambiguate from an unset value. The purpose of | ||
157 | // this field is to detect missing entries in environments where | ||
158 | // durability or ordering is not guaranteed. | ||
159 | SequenceIdWithinCall uint64 `protobuf:"varint,3,opt,name=sequence_id_within_call,json=sequenceIdWithinCall,proto3" json:"sequence_id_within_call,omitempty"` | ||
160 | Type GrpcLogEntry_EventType `protobuf:"varint,4,opt,name=type,proto3,enum=grpc.binarylog.v1.GrpcLogEntry_EventType" json:"type,omitempty"` | ||
161 | Logger GrpcLogEntry_Logger `protobuf:"varint,5,opt,name=logger,proto3,enum=grpc.binarylog.v1.GrpcLogEntry_Logger" json:"logger,omitempty"` | ||
162 | // The logger uses one of the following fields to record the payload, | ||
163 | // according to the type of the log entry. | ||
164 | // | ||
165 | // Types that are valid to be assigned to Payload: | ||
166 | // *GrpcLogEntry_ClientHeader | ||
167 | // *GrpcLogEntry_ServerHeader | ||
168 | // *GrpcLogEntry_Message | ||
169 | // *GrpcLogEntry_Trailer | ||
170 | Payload isGrpcLogEntry_Payload `protobuf_oneof:"payload"` | ||
171 | // true if payload does not represent the full message or metadata. | ||
172 | PayloadTruncated bool `protobuf:"varint,10,opt,name=payload_truncated,json=payloadTruncated,proto3" json:"payload_truncated,omitempty"` | ||
173 | // Peer address information, will only be recorded on the first | ||
174 | // incoming event. On client side, peer is logged on | ||
175 | // EVENT_TYPE_SERVER_HEADER normally or EVENT_TYPE_SERVER_TRAILER in | ||
176 | // the case of trailers-only. On server side, peer is always | ||
177 | // logged on EVENT_TYPE_CLIENT_HEADER. | ||
178 | Peer *Address `protobuf:"bytes,11,opt,name=peer,proto3" json:"peer,omitempty"` | ||
179 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
180 | XXX_unrecognized []byte `json:"-"` | ||
181 | XXX_sizecache int32 `json:"-"` | ||
182 | } | ||
183 | |||
184 | func (m *GrpcLogEntry) Reset() { *m = GrpcLogEntry{} } | ||
185 | func (m *GrpcLogEntry) String() string { return proto.CompactTextString(m) } | ||
186 | func (*GrpcLogEntry) ProtoMessage() {} | ||
187 | func (*GrpcLogEntry) Descriptor() ([]byte, []int) { | ||
188 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{0} | ||
189 | } | ||
190 | func (m *GrpcLogEntry) XXX_Unmarshal(b []byte) error { | ||
191 | return xxx_messageInfo_GrpcLogEntry.Unmarshal(m, b) | ||
192 | } | ||
193 | func (m *GrpcLogEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
194 | return xxx_messageInfo_GrpcLogEntry.Marshal(b, m, deterministic) | ||
195 | } | ||
196 | func (dst *GrpcLogEntry) XXX_Merge(src proto.Message) { | ||
197 | xxx_messageInfo_GrpcLogEntry.Merge(dst, src) | ||
198 | } | ||
199 | func (m *GrpcLogEntry) XXX_Size() int { | ||
200 | return xxx_messageInfo_GrpcLogEntry.Size(m) | ||
201 | } | ||
202 | func (m *GrpcLogEntry) XXX_DiscardUnknown() { | ||
203 | xxx_messageInfo_GrpcLogEntry.DiscardUnknown(m) | ||
204 | } | ||
205 | |||
206 | var xxx_messageInfo_GrpcLogEntry proto.InternalMessageInfo | ||
207 | |||
208 | func (m *GrpcLogEntry) GetTimestamp() *timestamp.Timestamp { | ||
209 | if m != nil { | ||
210 | return m.Timestamp | ||
211 | } | ||
212 | return nil | ||
213 | } | ||
214 | |||
215 | func (m *GrpcLogEntry) GetCallId() uint64 { | ||
216 | if m != nil { | ||
217 | return m.CallId | ||
218 | } | ||
219 | return 0 | ||
220 | } | ||
221 | |||
222 | func (m *GrpcLogEntry) GetSequenceIdWithinCall() uint64 { | ||
223 | if m != nil { | ||
224 | return m.SequenceIdWithinCall | ||
225 | } | ||
226 | return 0 | ||
227 | } | ||
228 | |||
229 | func (m *GrpcLogEntry) GetType() GrpcLogEntry_EventType { | ||
230 | if m != nil { | ||
231 | return m.Type | ||
232 | } | ||
233 | return GrpcLogEntry_EVENT_TYPE_UNKNOWN | ||
234 | } | ||
235 | |||
236 | func (m *GrpcLogEntry) GetLogger() GrpcLogEntry_Logger { | ||
237 | if m != nil { | ||
238 | return m.Logger | ||
239 | } | ||
240 | return GrpcLogEntry_LOGGER_UNKNOWN | ||
241 | } | ||
242 | |||
243 | type isGrpcLogEntry_Payload interface { | ||
244 | isGrpcLogEntry_Payload() | ||
245 | } | ||
246 | |||
247 | type GrpcLogEntry_ClientHeader struct { | ||
248 | ClientHeader *ClientHeader `protobuf:"bytes,6,opt,name=client_header,json=clientHeader,proto3,oneof"` | ||
249 | } | ||
250 | |||
251 | type GrpcLogEntry_ServerHeader struct { | ||
252 | ServerHeader *ServerHeader `protobuf:"bytes,7,opt,name=server_header,json=serverHeader,proto3,oneof"` | ||
253 | } | ||
254 | |||
255 | type GrpcLogEntry_Message struct { | ||
256 | Message *Message `protobuf:"bytes,8,opt,name=message,proto3,oneof"` | ||
257 | } | ||
258 | |||
259 | type GrpcLogEntry_Trailer struct { | ||
260 | Trailer *Trailer `protobuf:"bytes,9,opt,name=trailer,proto3,oneof"` | ||
261 | } | ||
262 | |||
263 | func (*GrpcLogEntry_ClientHeader) isGrpcLogEntry_Payload() {} | ||
264 | |||
265 | func (*GrpcLogEntry_ServerHeader) isGrpcLogEntry_Payload() {} | ||
266 | |||
267 | func (*GrpcLogEntry_Message) isGrpcLogEntry_Payload() {} | ||
268 | |||
269 | func (*GrpcLogEntry_Trailer) isGrpcLogEntry_Payload() {} | ||
270 | |||
271 | func (m *GrpcLogEntry) GetPayload() isGrpcLogEntry_Payload { | ||
272 | if m != nil { | ||
273 | return m.Payload | ||
274 | } | ||
275 | return nil | ||
276 | } | ||
277 | |||
278 | func (m *GrpcLogEntry) GetClientHeader() *ClientHeader { | ||
279 | if x, ok := m.GetPayload().(*GrpcLogEntry_ClientHeader); ok { | ||
280 | return x.ClientHeader | ||
281 | } | ||
282 | return nil | ||
283 | } | ||
284 | |||
285 | func (m *GrpcLogEntry) GetServerHeader() *ServerHeader { | ||
286 | if x, ok := m.GetPayload().(*GrpcLogEntry_ServerHeader); ok { | ||
287 | return x.ServerHeader | ||
288 | } | ||
289 | return nil | ||
290 | } | ||
291 | |||
292 | func (m *GrpcLogEntry) GetMessage() *Message { | ||
293 | if x, ok := m.GetPayload().(*GrpcLogEntry_Message); ok { | ||
294 | return x.Message | ||
295 | } | ||
296 | return nil | ||
297 | } | ||
298 | |||
299 | func (m *GrpcLogEntry) GetTrailer() *Trailer { | ||
300 | if x, ok := m.GetPayload().(*GrpcLogEntry_Trailer); ok { | ||
301 | return x.Trailer | ||
302 | } | ||
303 | return nil | ||
304 | } | ||
305 | |||
306 | func (m *GrpcLogEntry) GetPayloadTruncated() bool { | ||
307 | if m != nil { | ||
308 | return m.PayloadTruncated | ||
309 | } | ||
310 | return false | ||
311 | } | ||
312 | |||
313 | func (m *GrpcLogEntry) GetPeer() *Address { | ||
314 | if m != nil { | ||
315 | return m.Peer | ||
316 | } | ||
317 | return nil | ||
318 | } | ||
319 | |||
320 | // XXX_OneofFuncs is for the internal use of the proto package. | ||
321 | func (*GrpcLogEntry) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { | ||
322 | return _GrpcLogEntry_OneofMarshaler, _GrpcLogEntry_OneofUnmarshaler, _GrpcLogEntry_OneofSizer, []interface{}{ | ||
323 | (*GrpcLogEntry_ClientHeader)(nil), | ||
324 | (*GrpcLogEntry_ServerHeader)(nil), | ||
325 | (*GrpcLogEntry_Message)(nil), | ||
326 | (*GrpcLogEntry_Trailer)(nil), | ||
327 | } | ||
328 | } | ||
329 | |||
330 | func _GrpcLogEntry_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { | ||
331 | m := msg.(*GrpcLogEntry) | ||
332 | // payload | ||
333 | switch x := m.Payload.(type) { | ||
334 | case *GrpcLogEntry_ClientHeader: | ||
335 | b.EncodeVarint(6<<3 | proto.WireBytes) | ||
336 | if err := b.EncodeMessage(x.ClientHeader); err != nil { | ||
337 | return err | ||
338 | } | ||
339 | case *GrpcLogEntry_ServerHeader: | ||
340 | b.EncodeVarint(7<<3 | proto.WireBytes) | ||
341 | if err := b.EncodeMessage(x.ServerHeader); err != nil { | ||
342 | return err | ||
343 | } | ||
344 | case *GrpcLogEntry_Message: | ||
345 | b.EncodeVarint(8<<3 | proto.WireBytes) | ||
346 | if err := b.EncodeMessage(x.Message); err != nil { | ||
347 | return err | ||
348 | } | ||
349 | case *GrpcLogEntry_Trailer: | ||
350 | b.EncodeVarint(9<<3 | proto.WireBytes) | ||
351 | if err := b.EncodeMessage(x.Trailer); err != nil { | ||
352 | return err | ||
353 | } | ||
354 | case nil: | ||
355 | default: | ||
356 | return fmt.Errorf("GrpcLogEntry.Payload has unexpected type %T", x) | ||
357 | } | ||
358 | return nil | ||
359 | } | ||
360 | |||
361 | func _GrpcLogEntry_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { | ||
362 | m := msg.(*GrpcLogEntry) | ||
363 | switch tag { | ||
364 | case 6: // payload.client_header | ||
365 | if wire != proto.WireBytes { | ||
366 | return true, proto.ErrInternalBadWireType | ||
367 | } | ||
368 | msg := new(ClientHeader) | ||
369 | err := b.DecodeMessage(msg) | ||
370 | m.Payload = &GrpcLogEntry_ClientHeader{msg} | ||
371 | return true, err | ||
372 | case 7: // payload.server_header | ||
373 | if wire != proto.WireBytes { | ||
374 | return true, proto.ErrInternalBadWireType | ||
375 | } | ||
376 | msg := new(ServerHeader) | ||
377 | err := b.DecodeMessage(msg) | ||
378 | m.Payload = &GrpcLogEntry_ServerHeader{msg} | ||
379 | return true, err | ||
380 | case 8: // payload.message | ||
381 | if wire != proto.WireBytes { | ||
382 | return true, proto.ErrInternalBadWireType | ||
383 | } | ||
384 | msg := new(Message) | ||
385 | err := b.DecodeMessage(msg) | ||
386 | m.Payload = &GrpcLogEntry_Message{msg} | ||
387 | return true, err | ||
388 | case 9: // payload.trailer | ||
389 | if wire != proto.WireBytes { | ||
390 | return true, proto.ErrInternalBadWireType | ||
391 | } | ||
392 | msg := new(Trailer) | ||
393 | err := b.DecodeMessage(msg) | ||
394 | m.Payload = &GrpcLogEntry_Trailer{msg} | ||
395 | return true, err | ||
396 | default: | ||
397 | return false, nil | ||
398 | } | ||
399 | } | ||
400 | |||
401 | func _GrpcLogEntry_OneofSizer(msg proto.Message) (n int) { | ||
402 | m := msg.(*GrpcLogEntry) | ||
403 | // payload | ||
404 | switch x := m.Payload.(type) { | ||
405 | case *GrpcLogEntry_ClientHeader: | ||
406 | s := proto.Size(x.ClientHeader) | ||
407 | n += 1 // tag and wire | ||
408 | n += proto.SizeVarint(uint64(s)) | ||
409 | n += s | ||
410 | case *GrpcLogEntry_ServerHeader: | ||
411 | s := proto.Size(x.ServerHeader) | ||
412 | n += 1 // tag and wire | ||
413 | n += proto.SizeVarint(uint64(s)) | ||
414 | n += s | ||
415 | case *GrpcLogEntry_Message: | ||
416 | s := proto.Size(x.Message) | ||
417 | n += 1 // tag and wire | ||
418 | n += proto.SizeVarint(uint64(s)) | ||
419 | n += s | ||
420 | case *GrpcLogEntry_Trailer: | ||
421 | s := proto.Size(x.Trailer) | ||
422 | n += 1 // tag and wire | ||
423 | n += proto.SizeVarint(uint64(s)) | ||
424 | n += s | ||
425 | case nil: | ||
426 | default: | ||
427 | panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) | ||
428 | } | ||
429 | return n | ||
430 | } | ||
431 | |||
432 | type ClientHeader struct { | ||
433 | // This contains only the metadata from the application. | ||
434 | Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` | ||
435 | // The name of the RPC method, which looks something like: | ||
436 | // /<service>/<method> | ||
437 | // Note the leading "/" character. | ||
438 | MethodName string `protobuf:"bytes,2,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"` | ||
439 | // A single process may be used to run multiple virtual | ||
440 | // servers with different identities. | ||
441 | // The authority is the name of such a server identitiy. | ||
442 | // It is typically a portion of the URI in the form of | ||
443 | // <host> or <host>:<port> . | ||
444 | Authority string `protobuf:"bytes,3,opt,name=authority,proto3" json:"authority,omitempty"` | ||
445 | // the RPC timeout | ||
446 | Timeout *duration.Duration `protobuf:"bytes,4,opt,name=timeout,proto3" json:"timeout,omitempty"` | ||
447 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
448 | XXX_unrecognized []byte `json:"-"` | ||
449 | XXX_sizecache int32 `json:"-"` | ||
450 | } | ||
451 | |||
452 | func (m *ClientHeader) Reset() { *m = ClientHeader{} } | ||
453 | func (m *ClientHeader) String() string { return proto.CompactTextString(m) } | ||
454 | func (*ClientHeader) ProtoMessage() {} | ||
455 | func (*ClientHeader) Descriptor() ([]byte, []int) { | ||
456 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{1} | ||
457 | } | ||
458 | func (m *ClientHeader) XXX_Unmarshal(b []byte) error { | ||
459 | return xxx_messageInfo_ClientHeader.Unmarshal(m, b) | ||
460 | } | ||
461 | func (m *ClientHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
462 | return xxx_messageInfo_ClientHeader.Marshal(b, m, deterministic) | ||
463 | } | ||
464 | func (dst *ClientHeader) XXX_Merge(src proto.Message) { | ||
465 | xxx_messageInfo_ClientHeader.Merge(dst, src) | ||
466 | } | ||
467 | func (m *ClientHeader) XXX_Size() int { | ||
468 | return xxx_messageInfo_ClientHeader.Size(m) | ||
469 | } | ||
470 | func (m *ClientHeader) XXX_DiscardUnknown() { | ||
471 | xxx_messageInfo_ClientHeader.DiscardUnknown(m) | ||
472 | } | ||
473 | |||
474 | var xxx_messageInfo_ClientHeader proto.InternalMessageInfo | ||
475 | |||
476 | func (m *ClientHeader) GetMetadata() *Metadata { | ||
477 | if m != nil { | ||
478 | return m.Metadata | ||
479 | } | ||
480 | return nil | ||
481 | } | ||
482 | |||
483 | func (m *ClientHeader) GetMethodName() string { | ||
484 | if m != nil { | ||
485 | return m.MethodName | ||
486 | } | ||
487 | return "" | ||
488 | } | ||
489 | |||
490 | func (m *ClientHeader) GetAuthority() string { | ||
491 | if m != nil { | ||
492 | return m.Authority | ||
493 | } | ||
494 | return "" | ||
495 | } | ||
496 | |||
497 | func (m *ClientHeader) GetTimeout() *duration.Duration { | ||
498 | if m != nil { | ||
499 | return m.Timeout | ||
500 | } | ||
501 | return nil | ||
502 | } | ||
503 | |||
504 | type ServerHeader struct { | ||
505 | // This contains only the metadata from the application. | ||
506 | Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` | ||
507 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
508 | XXX_unrecognized []byte `json:"-"` | ||
509 | XXX_sizecache int32 `json:"-"` | ||
510 | } | ||
511 | |||
512 | func (m *ServerHeader) Reset() { *m = ServerHeader{} } | ||
513 | func (m *ServerHeader) String() string { return proto.CompactTextString(m) } | ||
514 | func (*ServerHeader) ProtoMessage() {} | ||
515 | func (*ServerHeader) Descriptor() ([]byte, []int) { | ||
516 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{2} | ||
517 | } | ||
518 | func (m *ServerHeader) XXX_Unmarshal(b []byte) error { | ||
519 | return xxx_messageInfo_ServerHeader.Unmarshal(m, b) | ||
520 | } | ||
521 | func (m *ServerHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
522 | return xxx_messageInfo_ServerHeader.Marshal(b, m, deterministic) | ||
523 | } | ||
524 | func (dst *ServerHeader) XXX_Merge(src proto.Message) { | ||
525 | xxx_messageInfo_ServerHeader.Merge(dst, src) | ||
526 | } | ||
527 | func (m *ServerHeader) XXX_Size() int { | ||
528 | return xxx_messageInfo_ServerHeader.Size(m) | ||
529 | } | ||
530 | func (m *ServerHeader) XXX_DiscardUnknown() { | ||
531 | xxx_messageInfo_ServerHeader.DiscardUnknown(m) | ||
532 | } | ||
533 | |||
534 | var xxx_messageInfo_ServerHeader proto.InternalMessageInfo | ||
535 | |||
536 | func (m *ServerHeader) GetMetadata() *Metadata { | ||
537 | if m != nil { | ||
538 | return m.Metadata | ||
539 | } | ||
540 | return nil | ||
541 | } | ||
542 | |||
543 | type Trailer struct { | ||
544 | // This contains only the metadata from the application. | ||
545 | Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` | ||
546 | // The gRPC status code. | ||
547 | StatusCode uint32 `protobuf:"varint,2,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` | ||
548 | // An original status message before any transport specific | ||
549 | // encoding. | ||
550 | StatusMessage string `protobuf:"bytes,3,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` | ||
551 | // The value of the 'grpc-status-details-bin' metadata key. If | ||
552 | // present, this is always an encoded 'google.rpc.Status' message. | ||
553 | StatusDetails []byte `protobuf:"bytes,4,opt,name=status_details,json=statusDetails,proto3" json:"status_details,omitempty"` | ||
554 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
555 | XXX_unrecognized []byte `json:"-"` | ||
556 | XXX_sizecache int32 `json:"-"` | ||
557 | } | ||
558 | |||
559 | func (m *Trailer) Reset() { *m = Trailer{} } | ||
560 | func (m *Trailer) String() string { return proto.CompactTextString(m) } | ||
561 | func (*Trailer) ProtoMessage() {} | ||
562 | func (*Trailer) Descriptor() ([]byte, []int) { | ||
563 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{3} | ||
564 | } | ||
565 | func (m *Trailer) XXX_Unmarshal(b []byte) error { | ||
566 | return xxx_messageInfo_Trailer.Unmarshal(m, b) | ||
567 | } | ||
568 | func (m *Trailer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
569 | return xxx_messageInfo_Trailer.Marshal(b, m, deterministic) | ||
570 | } | ||
571 | func (dst *Trailer) XXX_Merge(src proto.Message) { | ||
572 | xxx_messageInfo_Trailer.Merge(dst, src) | ||
573 | } | ||
574 | func (m *Trailer) XXX_Size() int { | ||
575 | return xxx_messageInfo_Trailer.Size(m) | ||
576 | } | ||
577 | func (m *Trailer) XXX_DiscardUnknown() { | ||
578 | xxx_messageInfo_Trailer.DiscardUnknown(m) | ||
579 | } | ||
580 | |||
581 | var xxx_messageInfo_Trailer proto.InternalMessageInfo | ||
582 | |||
583 | func (m *Trailer) GetMetadata() *Metadata { | ||
584 | if m != nil { | ||
585 | return m.Metadata | ||
586 | } | ||
587 | return nil | ||
588 | } | ||
589 | |||
590 | func (m *Trailer) GetStatusCode() uint32 { | ||
591 | if m != nil { | ||
592 | return m.StatusCode | ||
593 | } | ||
594 | return 0 | ||
595 | } | ||
596 | |||
597 | func (m *Trailer) GetStatusMessage() string { | ||
598 | if m != nil { | ||
599 | return m.StatusMessage | ||
600 | } | ||
601 | return "" | ||
602 | } | ||
603 | |||
604 | func (m *Trailer) GetStatusDetails() []byte { | ||
605 | if m != nil { | ||
606 | return m.StatusDetails | ||
607 | } | ||
608 | return nil | ||
609 | } | ||
610 | |||
611 | // Message payload, used by CLIENT_MESSAGE and SERVER_MESSAGE | ||
612 | type Message struct { | ||
613 | // Length of the message. It may not be the same as the length of the | ||
614 | // data field, as the logging payload can be truncated or omitted. | ||
615 | Length uint32 `protobuf:"varint,1,opt,name=length,proto3" json:"length,omitempty"` | ||
616 | // May be truncated or omitted. | ||
617 | Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` | ||
618 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
619 | XXX_unrecognized []byte `json:"-"` | ||
620 | XXX_sizecache int32 `json:"-"` | ||
621 | } | ||
622 | |||
623 | func (m *Message) Reset() { *m = Message{} } | ||
624 | func (m *Message) String() string { return proto.CompactTextString(m) } | ||
625 | func (*Message) ProtoMessage() {} | ||
626 | func (*Message) Descriptor() ([]byte, []int) { | ||
627 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{4} | ||
628 | } | ||
629 | func (m *Message) XXX_Unmarshal(b []byte) error { | ||
630 | return xxx_messageInfo_Message.Unmarshal(m, b) | ||
631 | } | ||
632 | func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
633 | return xxx_messageInfo_Message.Marshal(b, m, deterministic) | ||
634 | } | ||
635 | func (dst *Message) XXX_Merge(src proto.Message) { | ||
636 | xxx_messageInfo_Message.Merge(dst, src) | ||
637 | } | ||
638 | func (m *Message) XXX_Size() int { | ||
639 | return xxx_messageInfo_Message.Size(m) | ||
640 | } | ||
641 | func (m *Message) XXX_DiscardUnknown() { | ||
642 | xxx_messageInfo_Message.DiscardUnknown(m) | ||
643 | } | ||
644 | |||
645 | var xxx_messageInfo_Message proto.InternalMessageInfo | ||
646 | |||
647 | func (m *Message) GetLength() uint32 { | ||
648 | if m != nil { | ||
649 | return m.Length | ||
650 | } | ||
651 | return 0 | ||
652 | } | ||
653 | |||
654 | func (m *Message) GetData() []byte { | ||
655 | if m != nil { | ||
656 | return m.Data | ||
657 | } | ||
658 | return nil | ||
659 | } | ||
660 | |||
661 | // A list of metadata pairs, used in the payload of client header, | ||
662 | // server header, and server trailer. | ||
663 | // Implementations may omit some entries to honor the header limits | ||
664 | // of GRPC_BINARY_LOG_CONFIG. | ||
665 | // | ||
666 | // Header keys added by gRPC are omitted. To be more specific, | ||
667 | // implementations will not log the following entries, and this is | ||
668 | // not to be treated as a truncation: | ||
669 | // - entries handled by grpc that are not user visible, such as those | ||
670 | // that begin with 'grpc-' (with exception of grpc-trace-bin) | ||
671 | // or keys like 'lb-token' | ||
672 | // - transport specific entries, including but not limited to: | ||
673 | // ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc | ||
674 | // - entries added for call credentials | ||
675 | // | ||
676 | // Implementations must always log grpc-trace-bin if it is present. | ||
677 | // Practically speaking it will only be visible on server side because | ||
678 | // grpc-trace-bin is managed by low level client side mechanisms | ||
679 | // inaccessible from the application level. On server side, the | ||
680 | // header is just a normal metadata key. | ||
681 | // The pair will not count towards the size limit. | ||
682 | type Metadata struct { | ||
683 | Entry []*MetadataEntry `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"` | ||
684 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
685 | XXX_unrecognized []byte `json:"-"` | ||
686 | XXX_sizecache int32 `json:"-"` | ||
687 | } | ||
688 | |||
689 | func (m *Metadata) Reset() { *m = Metadata{} } | ||
690 | func (m *Metadata) String() string { return proto.CompactTextString(m) } | ||
691 | func (*Metadata) ProtoMessage() {} | ||
692 | func (*Metadata) Descriptor() ([]byte, []int) { | ||
693 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{5} | ||
694 | } | ||
695 | func (m *Metadata) XXX_Unmarshal(b []byte) error { | ||
696 | return xxx_messageInfo_Metadata.Unmarshal(m, b) | ||
697 | } | ||
698 | func (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
699 | return xxx_messageInfo_Metadata.Marshal(b, m, deterministic) | ||
700 | } | ||
701 | func (dst *Metadata) XXX_Merge(src proto.Message) { | ||
702 | xxx_messageInfo_Metadata.Merge(dst, src) | ||
703 | } | ||
704 | func (m *Metadata) XXX_Size() int { | ||
705 | return xxx_messageInfo_Metadata.Size(m) | ||
706 | } | ||
707 | func (m *Metadata) XXX_DiscardUnknown() { | ||
708 | xxx_messageInfo_Metadata.DiscardUnknown(m) | ||
709 | } | ||
710 | |||
711 | var xxx_messageInfo_Metadata proto.InternalMessageInfo | ||
712 | |||
713 | func (m *Metadata) GetEntry() []*MetadataEntry { | ||
714 | if m != nil { | ||
715 | return m.Entry | ||
716 | } | ||
717 | return nil | ||
718 | } | ||
719 | |||
720 | // A metadata key value pair | ||
721 | type MetadataEntry struct { | ||
722 | Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` | ||
723 | Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` | ||
724 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
725 | XXX_unrecognized []byte `json:"-"` | ||
726 | XXX_sizecache int32 `json:"-"` | ||
727 | } | ||
728 | |||
729 | func (m *MetadataEntry) Reset() { *m = MetadataEntry{} } | ||
730 | func (m *MetadataEntry) String() string { return proto.CompactTextString(m) } | ||
731 | func (*MetadataEntry) ProtoMessage() {} | ||
732 | func (*MetadataEntry) Descriptor() ([]byte, []int) { | ||
733 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{6} | ||
734 | } | ||
735 | func (m *MetadataEntry) XXX_Unmarshal(b []byte) error { | ||
736 | return xxx_messageInfo_MetadataEntry.Unmarshal(m, b) | ||
737 | } | ||
738 | func (m *MetadataEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
739 | return xxx_messageInfo_MetadataEntry.Marshal(b, m, deterministic) | ||
740 | } | ||
741 | func (dst *MetadataEntry) XXX_Merge(src proto.Message) { | ||
742 | xxx_messageInfo_MetadataEntry.Merge(dst, src) | ||
743 | } | ||
744 | func (m *MetadataEntry) XXX_Size() int { | ||
745 | return xxx_messageInfo_MetadataEntry.Size(m) | ||
746 | } | ||
747 | func (m *MetadataEntry) XXX_DiscardUnknown() { | ||
748 | xxx_messageInfo_MetadataEntry.DiscardUnknown(m) | ||
749 | } | ||
750 | |||
751 | var xxx_messageInfo_MetadataEntry proto.InternalMessageInfo | ||
752 | |||
753 | func (m *MetadataEntry) GetKey() string { | ||
754 | if m != nil { | ||
755 | return m.Key | ||
756 | } | ||
757 | return "" | ||
758 | } | ||
759 | |||
760 | func (m *MetadataEntry) GetValue() []byte { | ||
761 | if m != nil { | ||
762 | return m.Value | ||
763 | } | ||
764 | return nil | ||
765 | } | ||
766 | |||
767 | // Address information | ||
768 | type Address struct { | ||
769 | Type Address_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.binarylog.v1.Address_Type" json:"type,omitempty"` | ||
770 | Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` | ||
771 | // only for TYPE_IPV4 and TYPE_IPV6 | ||
772 | IpPort uint32 `protobuf:"varint,3,opt,name=ip_port,json=ipPort,proto3" json:"ip_port,omitempty"` | ||
773 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
774 | XXX_unrecognized []byte `json:"-"` | ||
775 | XXX_sizecache int32 `json:"-"` | ||
776 | } | ||
777 | |||
778 | func (m *Address) Reset() { *m = Address{} } | ||
779 | func (m *Address) String() string { return proto.CompactTextString(m) } | ||
780 | func (*Address) ProtoMessage() {} | ||
781 | func (*Address) Descriptor() ([]byte, []int) { | ||
782 | return fileDescriptor_binarylog_264c8c9c551ce911, []int{7} | ||
783 | } | ||
784 | func (m *Address) XXX_Unmarshal(b []byte) error { | ||
785 | return xxx_messageInfo_Address.Unmarshal(m, b) | ||
786 | } | ||
787 | func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
788 | return xxx_messageInfo_Address.Marshal(b, m, deterministic) | ||
789 | } | ||
790 | func (dst *Address) XXX_Merge(src proto.Message) { | ||
791 | xxx_messageInfo_Address.Merge(dst, src) | ||
792 | } | ||
793 | func (m *Address) XXX_Size() int { | ||
794 | return xxx_messageInfo_Address.Size(m) | ||
795 | } | ||
796 | func (m *Address) XXX_DiscardUnknown() { | ||
797 | xxx_messageInfo_Address.DiscardUnknown(m) | ||
798 | } | ||
799 | |||
800 | var xxx_messageInfo_Address proto.InternalMessageInfo | ||
801 | |||
802 | func (m *Address) GetType() Address_Type { | ||
803 | if m != nil { | ||
804 | return m.Type | ||
805 | } | ||
806 | return Address_TYPE_UNKNOWN | ||
807 | } | ||
808 | |||
809 | func (m *Address) GetAddress() string { | ||
810 | if m != nil { | ||
811 | return m.Address | ||
812 | } | ||
813 | return "" | ||
814 | } | ||
815 | |||
816 | func (m *Address) GetIpPort() uint32 { | ||
817 | if m != nil { | ||
818 | return m.IpPort | ||
819 | } | ||
820 | return 0 | ||
821 | } | ||
822 | |||
823 | func init() { | ||
824 | proto.RegisterType((*GrpcLogEntry)(nil), "grpc.binarylog.v1.GrpcLogEntry") | ||
825 | proto.RegisterType((*ClientHeader)(nil), "grpc.binarylog.v1.ClientHeader") | ||
826 | proto.RegisterType((*ServerHeader)(nil), "grpc.binarylog.v1.ServerHeader") | ||
827 | proto.RegisterType((*Trailer)(nil), "grpc.binarylog.v1.Trailer") | ||
828 | proto.RegisterType((*Message)(nil), "grpc.binarylog.v1.Message") | ||
829 | proto.RegisterType((*Metadata)(nil), "grpc.binarylog.v1.Metadata") | ||
830 | proto.RegisterType((*MetadataEntry)(nil), "grpc.binarylog.v1.MetadataEntry") | ||
831 | proto.RegisterType((*Address)(nil), "grpc.binarylog.v1.Address") | ||
832 | proto.RegisterEnum("grpc.binarylog.v1.GrpcLogEntry_EventType", GrpcLogEntry_EventType_name, GrpcLogEntry_EventType_value) | ||
833 | proto.RegisterEnum("grpc.binarylog.v1.GrpcLogEntry_Logger", GrpcLogEntry_Logger_name, GrpcLogEntry_Logger_value) | ||
834 | proto.RegisterEnum("grpc.binarylog.v1.Address_Type", Address_Type_name, Address_Type_value) | ||
835 | } | ||
836 | |||
837 | func init() { | ||
838 | proto.RegisterFile("grpc/binarylog/grpc_binarylog_v1/binarylog.proto", fileDescriptor_binarylog_264c8c9c551ce911) | ||
839 | } | ||
840 | |||
841 | var fileDescriptor_binarylog_264c8c9c551ce911 = []byte{ | ||
842 | // 900 bytes of a gzipped FileDescriptorProto | ||
843 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x51, 0x6f, 0xe3, 0x44, | ||
844 | 0x10, 0x3e, 0x37, 0x69, 0xdc, 0x4c, 0x92, 0xca, 0x5d, 0x95, 0x3b, 0x5f, 0x29, 0x34, 0xb2, 0x04, | ||
845 | 0x0a, 0x42, 0x72, 0xb9, 0x94, 0xeb, 0xf1, 0x02, 0x52, 0x92, 0xfa, 0xd2, 0x88, 0x5c, 0x1a, 0x6d, | ||
846 | 0x72, 0x3d, 0x40, 0x48, 0xd6, 0x36, 0x5e, 0x1c, 0x0b, 0xc7, 0x6b, 0xd6, 0x9b, 0xa0, 0xfc, 0x2c, | ||
847 | 0xde, 0x90, 0xee, 0x77, 0xf1, 0x8e, 0xbc, 0x6b, 0x27, 0xa6, 0x69, 0x0f, 0x09, 0xde, 0x3c, 0xdf, | ||
848 | 0x7c, 0xf3, 0xcd, 0xee, 0x78, 0x66, 0x16, 0xbe, 0xf2, 0x79, 0x3c, 0x3b, 0xbf, 0x0b, 0x22, 0xc2, | ||
849 | 0xd7, 0x21, 0xf3, 0xcf, 0x53, 0xd3, 0xdd, 0x98, 0xee, 0xea, 0xc5, 0xd6, 0x67, 0xc7, 0x9c, 0x09, | ||
850 | 0x86, 0x8e, 0x52, 0x8a, 0xbd, 0x45, 0x57, 0x2f, 0x4e, 0x3e, 0xf5, 0x19, 0xf3, 0x43, 0x7a, 0x2e, | ||
851 | 0x09, 0x77, 0xcb, 0x5f, 0xce, 0xbd, 0x25, 0x27, 0x22, 0x60, 0x91, 0x0a, 0x39, 0x39, 0xbb, 0xef, | ||
852 | 0x17, 0xc1, 0x82, 0x26, 0x82, 0x2c, 0x62, 0x45, 0xb0, 0xde, 0xeb, 0x50, 0xef, 0xf3, 0x78, 0x36, | ||
853 | 0x64, 0xbe, 0x13, 0x09, 0xbe, 0x46, 0xdf, 0x40, 0x75, 0xc3, 0x31, 0xb5, 0xa6, 0xd6, 0xaa, 0xb5, | ||
854 | 0x4f, 0x6c, 0xa5, 0x62, 0xe7, 0x2a, 0xf6, 0x34, 0x67, 0xe0, 0x2d, 0x19, 0x3d, 0x03, 0x7d, 0x46, | ||
855 | 0xc2, 0xd0, 0x0d, 0x3c, 0x73, 0xaf, 0xa9, 0xb5, 0xca, 0xb8, 0x92, 0x9a, 0x03, 0x0f, 0xbd, 0x84, | ||
856 | 0x67, 0x09, 0xfd, 0x6d, 0x49, 0xa3, 0x19, 0x75, 0x03, 0xcf, 0xfd, 0x3d, 0x10, 0xf3, 0x20, 0x72, | ||
857 | 0x53, 0xa7, 0x59, 0x92, 0xc4, 0xe3, 0xdc, 0x3d, 0xf0, 0xde, 0x49, 0x67, 0x8f, 0x84, 0x21, 0xfa, | ||
858 | 0x16, 0xca, 0x62, 0x1d, 0x53, 0xb3, 0xdc, 0xd4, 0x5a, 0x87, 0xed, 0x2f, 0xec, 0x9d, 0xdb, 0xdb, | ||
859 | 0xc5, 0x83, 0xdb, 0xce, 0x8a, 0x46, 0x62, 0xba, 0x8e, 0x29, 0x96, 0x61, 0xe8, 0x3b, 0xa8, 0x84, | ||
860 | 0xcc, 0xf7, 0x29, 0x37, 0xf7, 0xa5, 0xc0, 0xe7, 0xff, 0x26, 0x30, 0x94, 0x6c, 0x9c, 0x45, 0xa1, | ||
861 | 0xd7, 0xd0, 0x98, 0x85, 0x01, 0x8d, 0x84, 0x3b, 0xa7, 0xc4, 0xa3, 0xdc, 0xac, 0xc8, 0x62, 0x9c, | ||
862 | 0x3d, 0x20, 0xd3, 0x93, 0xbc, 0x6b, 0x49, 0xbb, 0x7e, 0x82, 0xeb, 0xb3, 0x82, 0x9d, 0xea, 0x24, | ||
863 | 0x94, 0xaf, 0x28, 0xcf, 0x75, 0xf4, 0x47, 0x75, 0x26, 0x92, 0xb7, 0xd5, 0x49, 0x0a, 0x36, 0xba, | ||
864 | 0x04, 0x7d, 0x41, 0x93, 0x84, 0xf8, 0xd4, 0x3c, 0xc8, 0x7f, 0xcb, 0x8e, 0xc2, 0x1b, 0xc5, 0xb8, | ||
865 | 0x7e, 0x82, 0x73, 0x72, 0x1a, 0x27, 0x38, 0x09, 0x42, 0xca, 0xcd, 0xea, 0xa3, 0x71, 0x53, 0xc5, | ||
866 | 0x48, 0xe3, 0x32, 0x32, 0xfa, 0x12, 0x8e, 0x62, 0xb2, 0x0e, 0x19, 0xf1, 0x5c, 0xc1, 0x97, 0xd1, | ||
867 | 0x8c, 0x08, 0xea, 0x99, 0xd0, 0xd4, 0x5a, 0x07, 0xd8, 0xc8, 0x1c, 0xd3, 0x1c, 0x47, 0x36, 0x94, | ||
868 | 0x63, 0x4a, 0xb9, 0x59, 0x7b, 0x34, 0x43, 0xc7, 0xf3, 0x38, 0x4d, 0x12, 0x2c, 0x79, 0xd6, 0x5f, | ||
869 | 0x1a, 0x54, 0x37, 0x3f, 0x0c, 0x3d, 0x05, 0xe4, 0xdc, 0x3a, 0xa3, 0xa9, 0x3b, 0xfd, 0x71, 0xec, | ||
870 | 0xb8, 0x6f, 0x47, 0xdf, 0x8f, 0x6e, 0xde, 0x8d, 0x8c, 0x27, 0xe8, 0x14, 0xcc, 0x02, 0xde, 0x1b, | ||
871 | 0x0e, 0xd2, 0xef, 0x6b, 0xa7, 0x73, 0xe5, 0x60, 0x43, 0xbb, 0xe7, 0x9d, 0x38, 0xf8, 0xd6, 0xc1, | ||
872 | 0xb9, 0x77, 0x0f, 0x7d, 0x02, 0xcf, 0x77, 0x63, 0xdf, 0x38, 0x93, 0x49, 0xa7, 0xef, 0x18, 0xa5, | ||
873 | 0x7b, 0xee, 0x2c, 0x38, 0x77, 0x97, 0x51, 0x13, 0x4e, 0x1f, 0xc8, 0xdc, 0x19, 0xbe, 0x76, 0x7b, | ||
874 | 0xc3, 0x9b, 0x89, 0x63, 0xec, 0x3f, 0x2c, 0x30, 0xc5, 0x9d, 0xc1, 0xd0, 0xc1, 0x46, 0x05, 0x7d, | ||
875 | 0x04, 0x47, 0x45, 0x81, 0xce, 0xa8, 0xe7, 0x0c, 0x0d, 0xdd, 0xea, 0x42, 0x45, 0xb5, 0x19, 0x42, | ||
876 | 0x70, 0x38, 0xbc, 0xe9, 0xf7, 0x1d, 0x5c, 0xb8, 0xef, 0x11, 0x34, 0x32, 0x4c, 0x65, 0x34, 0xb4, | ||
877 | 0x02, 0xa4, 0x52, 0x18, 0x7b, 0xdd, 0x2a, 0xe8, 0x59, 0xfd, 0xad, 0xf7, 0x1a, 0xd4, 0x8b, 0xcd, | ||
878 | 0x87, 0x5e, 0xc1, 0xc1, 0x82, 0x0a, 0xe2, 0x11, 0x41, 0xb2, 0xe1, 0xfd, 0xf8, 0xc1, 0x2e, 0x51, | ||
879 | 0x14, 0xbc, 0x21, 0xa3, 0x33, 0xa8, 0x2d, 0xa8, 0x98, 0x33, 0xcf, 0x8d, 0xc8, 0x82, 0xca, 0x01, | ||
880 | 0xae, 0x62, 0x50, 0xd0, 0x88, 0x2c, 0x28, 0x3a, 0x85, 0x2a, 0x59, 0x8a, 0x39, 0xe3, 0x81, 0x58, | ||
881 | 0xcb, 0xb1, 0xad, 0xe2, 0x2d, 0x80, 0x2e, 0x40, 0x4f, 0x17, 0x01, 0x5b, 0x0a, 0x39, 0xae, 0xb5, | ||
882 | 0xf6, 0xf3, 0x9d, 0x9d, 0x71, 0x95, 0x6d, 0x26, 0x9c, 0x33, 0xad, 0x3e, 0xd4, 0x8b, 0x1d, 0xff, | ||
883 | 0x9f, 0x0f, 0x6f, 0xfd, 0xa1, 0x81, 0x9e, 0x75, 0xf0, 0xff, 0xaa, 0x40, 0x22, 0x88, 0x58, 0x26, | ||
884 | 0xee, 0x8c, 0x79, 0xaa, 0x02, 0x0d, 0x0c, 0x0a, 0xea, 0x31, 0x8f, 0xa2, 0xcf, 0xe0, 0x30, 0x23, | ||
885 | 0xe4, 0x73, 0xa8, 0xca, 0xd0, 0x50, 0x68, 0x36, 0x7a, 0x05, 0x9a, 0x47, 0x05, 0x09, 0xc2, 0x44, | ||
886 | 0x56, 0xa4, 0x9e, 0xd3, 0xae, 0x14, 0x68, 0xbd, 0x04, 0x3d, 0x8f, 0x78, 0x0a, 0x95, 0x90, 0x46, | ||
887 | 0xbe, 0x98, 0xcb, 0x03, 0x37, 0x70, 0x66, 0x21, 0x04, 0x65, 0x79, 0x8d, 0x3d, 0x19, 0x2f, 0xbf, | ||
888 | 0xad, 0x2e, 0x1c, 0xe4, 0x67, 0x47, 0x97, 0xb0, 0x4f, 0xd3, 0xcd, 0x65, 0x6a, 0xcd, 0x52, 0xab, | ||
889 | 0xd6, 0x6e, 0x7e, 0xe0, 0x9e, 0x72, 0xc3, 0x61, 0x45, 0xb7, 0x5e, 0x41, 0xe3, 0x1f, 0x38, 0x32, | ||
890 | 0xa0, 0xf4, 0x2b, 0x5d, 0xcb, 0xec, 0x55, 0x9c, 0x7e, 0xa2, 0x63, 0xd8, 0x5f, 0x91, 0x70, 0x49, | ||
891 | 0xb3, 0xdc, 0xca, 0xb0, 0xfe, 0xd4, 0x40, 0xcf, 0xe6, 0x18, 0x5d, 0x64, 0xdb, 0x59, 0x93, 0xcb, | ||
892 | 0xf5, 0xec, 0xf1, 0x89, 0xb7, 0x0b, 0x3b, 0xd9, 0x04, 0x9d, 0x28, 0x34, 0xeb, 0xb0, 0xdc, 0x4c, | ||
893 | 0x1f, 0x8f, 0x20, 0x76, 0x63, 0xc6, 0x85, 0xac, 0x6a, 0x03, 0x57, 0x82, 0x78, 0xcc, 0xb8, 0xb0, | ||
894 | 0x1c, 0x28, 0xcb, 0x1d, 0x61, 0x40, 0xfd, 0xde, 0x76, 0x68, 0x40, 0x55, 0x22, 0x83, 0xf1, 0xed, | ||
895 | 0xd7, 0x86, 0x56, 0x34, 0x2f, 0x8d, 0xbd, 0x8d, 0xf9, 0x76, 0x34, 0xf8, 0xc1, 0x28, 0x75, 0x7f, | ||
896 | 0x86, 0xe3, 0x80, 0xed, 0x1e, 0xb2, 0x7b, 0xd8, 0x95, 0xd6, 0x90, 0xf9, 0xe3, 0xb4, 0x51, 0xc7, | ||
897 | 0xda, 0x4f, 0xed, 0xac, 0x71, 0x7d, 0x16, 0x92, 0xc8, 0xb7, 0x19, 0x57, 0x4f, 0xf3, 0x87, 0x5e, | ||
898 | 0xea, 0xbb, 0x8a, 0xec, 0xf2, 0x8b, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xf6, 0x4b, 0x50, | ||
899 | 0xd4, 0x07, 0x00, 0x00, | ||
900 | } | ||
diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go index 797190f..100f05d 100644 --- a/vendor/google.golang.org/grpc/call.go +++ b/vendor/google.golang.org/grpc/call.go | |||
@@ -19,291 +19,56 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "context" |
23 | "io" | ||
24 | "time" | ||
25 | |||
26 | "golang.org/x/net/context" | ||
27 | "golang.org/x/net/trace" | ||
28 | "google.golang.org/grpc/codes" | ||
29 | "google.golang.org/grpc/peer" | ||
30 | "google.golang.org/grpc/stats" | ||
31 | "google.golang.org/grpc/status" | ||
32 | "google.golang.org/grpc/transport" | ||
33 | ) | 23 | ) |
34 | 24 | ||
35 | // recvResponse receives and parses an RPC response. | 25 | // Invoke sends the RPC request on the wire and returns after response is |
36 | // On error, it returns the error and indicates whether the call should be retried. | 26 | // received. This is typically called by generated code. |
37 | // | 27 | // |
38 | // TODO(zhaoq): Check whether the received message sequence is valid. | 28 | // All errors returned by Invoke are compatible with the status package. |
39 | // TODO ctx is used for stats collection and processing. It is the context passed from the application. | 29 | func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error { |
40 | func recvResponse(ctx context.Context, dopts dialOptions, t transport.ClientTransport, c *callInfo, stream *transport.Stream, reply interface{}) (err error) { | 30 | // allow interceptor to see all applicable call options, which means those |
41 | // Try to acquire header metadata from the server if there is any. | 31 | // configured as defaults from dial option as well as per-call options |
42 | defer func() { | 32 | opts = combine(cc.dopts.callOptions, opts) |
43 | if err != nil { | ||
44 | if _, ok := err.(transport.ConnectionError); !ok { | ||
45 | t.CloseStream(stream, err) | ||
46 | } | ||
47 | } | ||
48 | }() | ||
49 | c.headerMD, err = stream.Header() | ||
50 | if err != nil { | ||
51 | return | ||
52 | } | ||
53 | p := &parser{r: stream} | ||
54 | var inPayload *stats.InPayload | ||
55 | if dopts.copts.StatsHandler != nil { | ||
56 | inPayload = &stats.InPayload{ | ||
57 | Client: true, | ||
58 | } | ||
59 | } | ||
60 | for { | ||
61 | if c.maxReceiveMessageSize == nil { | ||
62 | return Errorf(codes.Internal, "callInfo maxReceiveMessageSize field uninitialized(nil)") | ||
63 | } | ||
64 | if err = recv(p, dopts.codec, stream, dopts.dc, reply, *c.maxReceiveMessageSize, inPayload); err != nil { | ||
65 | if err == io.EOF { | ||
66 | break | ||
67 | } | ||
68 | return | ||
69 | } | ||
70 | } | ||
71 | if inPayload != nil && err == io.EOF && stream.Status().Code() == codes.OK { | ||
72 | // TODO in the current implementation, inTrailer may be handled before inPayload in some cases. | ||
73 | // Fix the order if necessary. | ||
74 | dopts.copts.StatsHandler.HandleRPC(ctx, inPayload) | ||
75 | } | ||
76 | c.trailerMD = stream.Trailer() | ||
77 | return nil | ||
78 | } | ||
79 | |||
80 | // sendRequest writes out various information of an RPC such as Context and Message. | ||
81 | func sendRequest(ctx context.Context, dopts dialOptions, compressor Compressor, c *callInfo, callHdr *transport.CallHdr, stream *transport.Stream, t transport.ClientTransport, args interface{}, opts *transport.Options) (err error) { | ||
82 | defer func() { | ||
83 | if err != nil { | ||
84 | // If err is connection error, t will be closed, no need to close stream here. | ||
85 | if _, ok := err.(transport.ConnectionError); !ok { | ||
86 | t.CloseStream(stream, err) | ||
87 | } | ||
88 | } | ||
89 | }() | ||
90 | var ( | ||
91 | cbuf *bytes.Buffer | ||
92 | outPayload *stats.OutPayload | ||
93 | ) | ||
94 | if compressor != nil { | ||
95 | cbuf = new(bytes.Buffer) | ||
96 | } | ||
97 | if dopts.copts.StatsHandler != nil { | ||
98 | outPayload = &stats.OutPayload{ | ||
99 | Client: true, | ||
100 | } | ||
101 | } | ||
102 | outBuf, err := encode(dopts.codec, args, compressor, cbuf, outPayload) | ||
103 | if err != nil { | ||
104 | return err | ||
105 | } | ||
106 | if c.maxSendMessageSize == nil { | ||
107 | return Errorf(codes.Internal, "callInfo maxSendMessageSize field uninitialized(nil)") | ||
108 | } | ||
109 | if len(outBuf) > *c.maxSendMessageSize { | ||
110 | return Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(outBuf), *c.maxSendMessageSize) | ||
111 | } | ||
112 | err = t.Write(stream, outBuf, opts) | ||
113 | if err == nil && outPayload != nil { | ||
114 | outPayload.SentTime = time.Now() | ||
115 | dopts.copts.StatsHandler.HandleRPC(ctx, outPayload) | ||
116 | } | ||
117 | // t.NewStream(...) could lead to an early rejection of the RPC (e.g., the service/method | ||
118 | // does not exist.) so that t.Write could get io.EOF from wait(...). Leave the following | ||
119 | // recvResponse to get the final status. | ||
120 | if err != nil && err != io.EOF { | ||
121 | return err | ||
122 | } | ||
123 | // Sent successfully. | ||
124 | return nil | ||
125 | } | ||
126 | 33 | ||
127 | // Invoke sends the RPC request on the wire and returns after response is received. | ||
128 | // Invoke is called by generated code. Also users can call Invoke directly when it | ||
129 | // is really needed in their use cases. | ||
130 | func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) error { | ||
131 | if cc.dopts.unaryInt != nil { | 34 | if cc.dopts.unaryInt != nil { |
132 | return cc.dopts.unaryInt(ctx, method, args, reply, cc, invoke, opts...) | 35 | return cc.dopts.unaryInt(ctx, method, args, reply, cc, invoke, opts...) |
133 | } | 36 | } |
134 | return invoke(ctx, method, args, reply, cc, opts...) | 37 | return invoke(ctx, method, args, reply, cc, opts...) |
135 | } | 38 | } |
136 | 39 | ||
137 | func invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) (e error) { | 40 | func combine(o1 []CallOption, o2 []CallOption) []CallOption { |
138 | c := defaultCallInfo | 41 | // we don't use append because o1 could have extra capacity whose |
139 | mc := cc.GetMethodConfig(method) | 42 | // elements would be overwritten, which could cause inadvertent |
140 | if mc.WaitForReady != nil { | 43 | // sharing (and race connditions) between concurrent calls |
141 | c.failFast = !*mc.WaitForReady | 44 | if len(o1) == 0 { |
142 | } | 45 | return o2 |
143 | 46 | } else if len(o2) == 0 { | |
144 | if mc.Timeout != nil && *mc.Timeout >= 0 { | 47 | return o1 |
145 | var cancel context.CancelFunc | 48 | } |
146 | ctx, cancel = context.WithTimeout(ctx, *mc.Timeout) | 49 | ret := make([]CallOption, len(o1)+len(o2)) |
147 | defer cancel() | 50 | copy(ret, o1) |
148 | } | 51 | copy(ret[len(o1):], o2) |
52 | return ret | ||
53 | } | ||
149 | 54 | ||
150 | opts = append(cc.dopts.callOptions, opts...) | 55 | // Invoke sends the RPC request on the wire and returns after response is |
151 | for _, o := range opts { | 56 | // received. This is typically called by generated code. |
152 | if err := o.before(&c); err != nil { | 57 | // |
153 | return toRPCErr(err) | 58 | // DEPRECATED: Use ClientConn.Invoke instead. |
154 | } | 59 | func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) error { |
155 | } | 60 | return cc.Invoke(ctx, method, args, reply, opts...) |
156 | defer func() { | 61 | } |
157 | for _, o := range opts { | ||
158 | o.after(&c) | ||
159 | } | ||
160 | }() | ||
161 | 62 | ||
162 | c.maxSendMessageSize = getMaxSize(mc.MaxReqSize, c.maxSendMessageSize, defaultClientMaxSendMessageSize) | 63 | var unaryStreamDesc = &StreamDesc{ServerStreams: false, ClientStreams: false} |
163 | c.maxReceiveMessageSize = getMaxSize(mc.MaxRespSize, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) | ||
164 | 64 | ||
165 | if EnableTracing { | 65 | func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error { |
166 | c.traceInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) | 66 | cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...) |
167 | defer c.traceInfo.tr.Finish() | 67 | if err != nil { |
168 | c.traceInfo.firstLine.client = true | 68 | return err |
169 | if deadline, ok := ctx.Deadline(); ok { | ||
170 | c.traceInfo.firstLine.deadline = deadline.Sub(time.Now()) | ||
171 | } | ||
172 | c.traceInfo.tr.LazyLog(&c.traceInfo.firstLine, false) | ||
173 | // TODO(dsymonds): Arrange for c.traceInfo.firstLine.remoteAddr to be set. | ||
174 | defer func() { | ||
175 | if e != nil { | ||
176 | c.traceInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{e}}, true) | ||
177 | c.traceInfo.tr.SetError() | ||
178 | } | ||
179 | }() | ||
180 | } | ||
181 | ctx = newContextWithRPCInfo(ctx) | ||
182 | sh := cc.dopts.copts.StatsHandler | ||
183 | if sh != nil { | ||
184 | ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast}) | ||
185 | begin := &stats.Begin{ | ||
186 | Client: true, | ||
187 | BeginTime: time.Now(), | ||
188 | FailFast: c.failFast, | ||
189 | } | ||
190 | sh.HandleRPC(ctx, begin) | ||
191 | defer func() { | ||
192 | end := &stats.End{ | ||
193 | Client: true, | ||
194 | EndTime: time.Now(), | ||
195 | Error: e, | ||
196 | } | ||
197 | sh.HandleRPC(ctx, end) | ||
198 | }() | ||
199 | } | ||
200 | topts := &transport.Options{ | ||
201 | Last: true, | ||
202 | Delay: false, | ||
203 | } | 69 | } |
204 | for { | 70 | if err := cs.SendMsg(req); err != nil { |
205 | var ( | 71 | return err |
206 | err error | ||
207 | t transport.ClientTransport | ||
208 | stream *transport.Stream | ||
209 | // Record the put handler from Balancer.Get(...). It is called once the | ||
210 | // RPC has completed or failed. | ||
211 | put func() | ||
212 | ) | ||
213 | // TODO(zhaoq): Need a formal spec of fail-fast. | ||
214 | callHdr := &transport.CallHdr{ | ||
215 | Host: cc.authority, | ||
216 | Method: method, | ||
217 | } | ||
218 | if cc.dopts.cp != nil { | ||
219 | callHdr.SendCompress = cc.dopts.cp.Type() | ||
220 | } | ||
221 | if c.creds != nil { | ||
222 | callHdr.Creds = c.creds | ||
223 | } | ||
224 | |||
225 | gopts := BalancerGetOptions{ | ||
226 | BlockingWait: !c.failFast, | ||
227 | } | ||
228 | t, put, err = cc.getTransport(ctx, gopts) | ||
229 | if err != nil { | ||
230 | // TODO(zhaoq): Probably revisit the error handling. | ||
231 | if _, ok := status.FromError(err); ok { | ||
232 | return err | ||
233 | } | ||
234 | if err == errConnClosing || err == errConnUnavailable { | ||
235 | if c.failFast { | ||
236 | return Errorf(codes.Unavailable, "%v", err) | ||
237 | } | ||
238 | continue | ||
239 | } | ||
240 | // All the other errors are treated as Internal errors. | ||
241 | return Errorf(codes.Internal, "%v", err) | ||
242 | } | ||
243 | if c.traceInfo.tr != nil { | ||
244 | c.traceInfo.tr.LazyLog(&payload{sent: true, msg: args}, true) | ||
245 | } | ||
246 | stream, err = t.NewStream(ctx, callHdr) | ||
247 | if err != nil { | ||
248 | if put != nil { | ||
249 | if _, ok := err.(transport.ConnectionError); ok { | ||
250 | // If error is connection error, transport was sending data on wire, | ||
251 | // and we are not sure if anything has been sent on wire. | ||
252 | // If error is not connection error, we are sure nothing has been sent. | ||
253 | updateRPCInfoInContext(ctx, rpcInfo{bytesSent: true, bytesReceived: false}) | ||
254 | } | ||
255 | put() | ||
256 | } | ||
257 | if _, ok := err.(transport.ConnectionError); (ok || err == transport.ErrStreamDrain) && !c.failFast { | ||
258 | continue | ||
259 | } | ||
260 | return toRPCErr(err) | ||
261 | } | ||
262 | if peer, ok := peer.FromContext(stream.Context()); ok { | ||
263 | c.peer = peer | ||
264 | } | ||
265 | err = sendRequest(ctx, cc.dopts, cc.dopts.cp, &c, callHdr, stream, t, args, topts) | ||
266 | if err != nil { | ||
267 | if put != nil { | ||
268 | updateRPCInfoInContext(ctx, rpcInfo{ | ||
269 | bytesSent: stream.BytesSent(), | ||
270 | bytesReceived: stream.BytesReceived(), | ||
271 | }) | ||
272 | put() | ||
273 | } | ||
274 | // Retry a non-failfast RPC when | ||
275 | // i) there is a connection error; or | ||
276 | // ii) the server started to drain before this RPC was initiated. | ||
277 | if _, ok := err.(transport.ConnectionError); (ok || err == transport.ErrStreamDrain) && !c.failFast { | ||
278 | continue | ||
279 | } | ||
280 | return toRPCErr(err) | ||
281 | } | ||
282 | err = recvResponse(ctx, cc.dopts, t, &c, stream, reply) | ||
283 | if err != nil { | ||
284 | if put != nil { | ||
285 | updateRPCInfoInContext(ctx, rpcInfo{ | ||
286 | bytesSent: stream.BytesSent(), | ||
287 | bytesReceived: stream.BytesReceived(), | ||
288 | }) | ||
289 | put() | ||
290 | } | ||
291 | if _, ok := err.(transport.ConnectionError); (ok || err == transport.ErrStreamDrain) && !c.failFast { | ||
292 | continue | ||
293 | } | ||
294 | return toRPCErr(err) | ||
295 | } | ||
296 | if c.traceInfo.tr != nil { | ||
297 | c.traceInfo.tr.LazyLog(&payload{sent: false, msg: reply}, true) | ||
298 | } | ||
299 | t.CloseStream(stream, nil) | ||
300 | if put != nil { | ||
301 | updateRPCInfoInContext(ctx, rpcInfo{ | ||
302 | bytesSent: stream.BytesSent(), | ||
303 | bytesReceived: stream.BytesReceived(), | ||
304 | }) | ||
305 | put() | ||
306 | } | ||
307 | return stream.Status().Err() | ||
308 | } | 72 | } |
73 | return cs.RecvMsg(reply) | ||
309 | } | 74 | } |
diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index e3f6cb1..56d0bf7 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go | |||
@@ -19,35 +19,72 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "context" | ||
22 | "errors" | 23 | "errors" |
24 | "fmt" | ||
25 | "math" | ||
23 | "net" | 26 | "net" |
27 | "reflect" | ||
24 | "strings" | 28 | "strings" |
25 | "sync" | 29 | "sync" |
30 | "sync/atomic" | ||
26 | "time" | 31 | "time" |
27 | 32 | ||
28 | "golang.org/x/net/context" | 33 | "google.golang.org/grpc/balancer" |
29 | "golang.org/x/net/trace" | 34 | _ "google.golang.org/grpc/balancer/roundrobin" // To register roundrobin. |
35 | "google.golang.org/grpc/codes" | ||
30 | "google.golang.org/grpc/connectivity" | 36 | "google.golang.org/grpc/connectivity" |
31 | "google.golang.org/grpc/credentials" | 37 | "google.golang.org/grpc/credentials" |
32 | "google.golang.org/grpc/grpclog" | 38 | "google.golang.org/grpc/grpclog" |
39 | "google.golang.org/grpc/internal/backoff" | ||
40 | "google.golang.org/grpc/internal/channelz" | ||
41 | "google.golang.org/grpc/internal/envconfig" | ||
42 | "google.golang.org/grpc/internal/grpcsync" | ||
43 | "google.golang.org/grpc/internal/transport" | ||
33 | "google.golang.org/grpc/keepalive" | 44 | "google.golang.org/grpc/keepalive" |
34 | "google.golang.org/grpc/stats" | 45 | "google.golang.org/grpc/metadata" |
35 | "google.golang.org/grpc/transport" | 46 | "google.golang.org/grpc/resolver" |
47 | _ "google.golang.org/grpc/resolver/dns" // To register dns resolver. | ||
48 | _ "google.golang.org/grpc/resolver/passthrough" // To register passthrough resolver. | ||
49 | "google.golang.org/grpc/status" | ||
50 | ) | ||
51 | |||
52 | const ( | ||
53 | // minimum time to give a connection to complete | ||
54 | minConnectTimeout = 20 * time.Second | ||
55 | // must match grpclbName in grpclb/grpclb.go | ||
56 | grpclbName = "grpclb" | ||
36 | ) | 57 | ) |
37 | 58 | ||
38 | var ( | 59 | var ( |
39 | // ErrClientConnClosing indicates that the operation is illegal because | 60 | // ErrClientConnClosing indicates that the operation is illegal because |
40 | // the ClientConn is closing. | 61 | // the ClientConn is closing. |
41 | ErrClientConnClosing = errors.New("grpc: the client connection is closing") | 62 | // |
42 | // ErrClientConnTimeout indicates that the ClientConn cannot establish the | 63 | // Deprecated: this error should not be relied upon by users; use the status |
43 | // underlying connections within the specified timeout. | 64 | // code of Canceled instead. |
44 | // DEPRECATED: Please use context.DeadlineExceeded instead. | 65 | ErrClientConnClosing = status.Error(codes.Canceled, "grpc: the client connection is closing") |
45 | ErrClientConnTimeout = errors.New("grpc: timed out when dialing") | 66 | // errConnDrain indicates that the connection starts to be drained and does not accept any new RPCs. |
67 | errConnDrain = errors.New("grpc: the connection is drained") | ||
68 | // errConnClosing indicates that the connection is closing. | ||
69 | errConnClosing = errors.New("grpc: the connection is closing") | ||
70 | // errBalancerClosed indicates that the balancer is closed. | ||
71 | errBalancerClosed = errors.New("grpc: balancer is closed") | ||
72 | // We use an accessor so that minConnectTimeout can be | ||
73 | // atomically read and updated while testing. | ||
74 | getMinConnectTimeout = func() time.Duration { | ||
75 | return minConnectTimeout | ||
76 | } | ||
77 | ) | ||
46 | 78 | ||
79 | // The following errors are returned from Dial and DialContext | ||
80 | var ( | ||
47 | // errNoTransportSecurity indicates that there is no transport security | 81 | // errNoTransportSecurity indicates that there is no transport security |
48 | // being set for ClientConn. Users should either set one or explicitly | 82 | // being set for ClientConn. Users should either set one or explicitly |
49 | // call WithInsecure DialOption to disable security. | 83 | // call WithInsecure DialOption to disable security. |
50 | errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)") | 84 | errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)") |
85 | // errTransportCredsAndBundle indicates that creds bundle is used together | ||
86 | // with other individual Transport Credentials. | ||
87 | errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials") | ||
51 | // errTransportCredentialsMissing indicates that users want to transmit security | 88 | // errTransportCredentialsMissing indicates that users want to transmit security |
52 | // information (e.g., oauth2 token) which requires secure connection on an insecure | 89 | // information (e.g., oauth2 token) which requires secure connection on an insecure |
53 | // connection. | 90 | // connection. |
@@ -55,278 +92,100 @@ var ( | |||
55 | // errCredentialsConflict indicates that grpc.WithTransportCredentials() | 92 | // errCredentialsConflict indicates that grpc.WithTransportCredentials() |
56 | // and grpc.WithInsecure() are both called for a connection. | 93 | // and grpc.WithInsecure() are both called for a connection. |
57 | errCredentialsConflict = errors.New("grpc: transport credentials are set for an insecure connection (grpc.WithTransportCredentials() and grpc.WithInsecure() are both called)") | 94 | errCredentialsConflict = errors.New("grpc: transport credentials are set for an insecure connection (grpc.WithTransportCredentials() and grpc.WithInsecure() are both called)") |
58 | // errNetworkIO indicates that the connection is down due to some network I/O error. | ||
59 | errNetworkIO = errors.New("grpc: failed with network I/O error") | ||
60 | // errConnDrain indicates that the connection starts to be drained and does not accept any new RPCs. | ||
61 | errConnDrain = errors.New("grpc: the connection is drained") | ||
62 | // errConnClosing indicates that the connection is closing. | ||
63 | errConnClosing = errors.New("grpc: the connection is closing") | ||
64 | // errConnUnavailable indicates that the connection is unavailable. | ||
65 | errConnUnavailable = errors.New("grpc: the connection is unavailable") | ||
66 | // errBalancerClosed indicates that the balancer is closed. | ||
67 | errBalancerClosed = errors.New("grpc: balancer is closed") | ||
68 | // minimum time to give a connection to complete | ||
69 | minConnectTimeout = 20 * time.Second | ||
70 | ) | 95 | ) |
71 | 96 | ||
72 | // dialOptions configure a Dial call. dialOptions are set by the DialOption | ||
73 | // values passed to Dial. | ||
74 | type dialOptions struct { | ||
75 | unaryInt UnaryClientInterceptor | ||
76 | streamInt StreamClientInterceptor | ||
77 | codec Codec | ||
78 | cp Compressor | ||
79 | dc Decompressor | ||
80 | bs backoffStrategy | ||
81 | balancer Balancer | ||
82 | block bool | ||
83 | insecure bool | ||
84 | timeout time.Duration | ||
85 | scChan <-chan ServiceConfig | ||
86 | copts transport.ConnectOptions | ||
87 | callOptions []CallOption | ||
88 | } | ||
89 | |||
90 | const ( | 97 | const ( |
91 | defaultClientMaxReceiveMessageSize = 1024 * 1024 * 4 | 98 | defaultClientMaxReceiveMessageSize = 1024 * 1024 * 4 |
92 | defaultClientMaxSendMessageSize = 1024 * 1024 * 4 | 99 | defaultClientMaxSendMessageSize = math.MaxInt32 |
100 | // http2IOBufSize specifies the buffer size for sending frames. | ||
101 | defaultWriteBufSize = 32 * 1024 | ||
102 | defaultReadBufSize = 32 * 1024 | ||
93 | ) | 103 | ) |
94 | 104 | ||
95 | // DialOption configures how we set up the connection. | ||
96 | type DialOption func(*dialOptions) | ||
97 | |||
98 | // WithInitialWindowSize returns a DialOption which sets the value for initial window size on a stream. | ||
99 | // The lower bound for window size is 64K and any value smaller than that will be ignored. | ||
100 | func WithInitialWindowSize(s int32) DialOption { | ||
101 | return func(o *dialOptions) { | ||
102 | o.copts.InitialWindowSize = s | ||
103 | } | ||
104 | } | ||
105 | |||
106 | // WithInitialConnWindowSize returns a DialOption which sets the value for initial window size on a connection. | ||
107 | // The lower bound for window size is 64K and any value smaller than that will be ignored. | ||
108 | func WithInitialConnWindowSize(s int32) DialOption { | ||
109 | return func(o *dialOptions) { | ||
110 | o.copts.InitialConnWindowSize = s | ||
111 | } | ||
112 | } | ||
113 | |||
114 | // WithMaxMsgSize returns a DialOption which sets the maximum message size the client can receive. Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. | ||
115 | func WithMaxMsgSize(s int) DialOption { | ||
116 | return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) | ||
117 | } | ||
118 | |||
119 | // WithDefaultCallOptions returns a DialOption which sets the default CallOptions for calls over the connection. | ||
120 | func WithDefaultCallOptions(cos ...CallOption) DialOption { | ||
121 | return func(o *dialOptions) { | ||
122 | o.callOptions = append(o.callOptions, cos...) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | // WithCodec returns a DialOption which sets a codec for message marshaling and unmarshaling. | ||
127 | func WithCodec(c Codec) DialOption { | ||
128 | return func(o *dialOptions) { | ||
129 | o.codec = c | ||
130 | } | ||
131 | } | ||
132 | |||
133 | // WithCompressor returns a DialOption which sets a CompressorGenerator for generating message | ||
134 | // compressor. | ||
135 | func WithCompressor(cp Compressor) DialOption { | ||
136 | return func(o *dialOptions) { | ||
137 | o.cp = cp | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // WithDecompressor returns a DialOption which sets a DecompressorGenerator for generating | ||
142 | // message decompressor. | ||
143 | func WithDecompressor(dc Decompressor) DialOption { | ||
144 | return func(o *dialOptions) { | ||
145 | o.dc = dc | ||
146 | } | ||
147 | } | ||
148 | |||
149 | // WithBalancer returns a DialOption which sets a load balancer. | ||
150 | func WithBalancer(b Balancer) DialOption { | ||
151 | return func(o *dialOptions) { | ||
152 | o.balancer = b | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // WithServiceConfig returns a DialOption which has a channel to read the service configuration. | ||
157 | func WithServiceConfig(c <-chan ServiceConfig) DialOption { | ||
158 | return func(o *dialOptions) { | ||
159 | o.scChan = c | ||
160 | } | ||
161 | } | ||
162 | |||
163 | // WithBackoffMaxDelay configures the dialer to use the provided maximum delay | ||
164 | // when backing off after failed connection attempts. | ||
165 | func WithBackoffMaxDelay(md time.Duration) DialOption { | ||
166 | return WithBackoffConfig(BackoffConfig{MaxDelay: md}) | ||
167 | } | ||
168 | |||
169 | // WithBackoffConfig configures the dialer to use the provided backoff | ||
170 | // parameters after connection failures. | ||
171 | // | ||
172 | // Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up | ||
173 | // for use. | ||
174 | func WithBackoffConfig(b BackoffConfig) DialOption { | ||
175 | // Set defaults to ensure that provided BackoffConfig is valid and | ||
176 | // unexported fields get default values. | ||
177 | setDefaults(&b) | ||
178 | return withBackoff(b) | ||
179 | } | ||
180 | |||
181 | // withBackoff sets the backoff strategy used for retries after a | ||
182 | // failed connection attempt. | ||
183 | // | ||
184 | // This can be exported if arbitrary backoff strategies are allowed by gRPC. | ||
185 | func withBackoff(bs backoffStrategy) DialOption { | ||
186 | return func(o *dialOptions) { | ||
187 | o.bs = bs | ||
188 | } | ||
189 | } | ||
190 | |||
191 | // WithBlock returns a DialOption which makes caller of Dial blocks until the underlying | ||
192 | // connection is up. Without this, Dial returns immediately and connecting the server | ||
193 | // happens in background. | ||
194 | func WithBlock() DialOption { | ||
195 | return func(o *dialOptions) { | ||
196 | o.block = true | ||
197 | } | ||
198 | } | ||
199 | |||
200 | // WithInsecure returns a DialOption which disables transport security for this ClientConn. | ||
201 | // Note that transport security is required unless WithInsecure is set. | ||
202 | func WithInsecure() DialOption { | ||
203 | return func(o *dialOptions) { | ||
204 | o.insecure = true | ||
205 | } | ||
206 | } | ||
207 | |||
208 | // WithTransportCredentials returns a DialOption which configures a | ||
209 | // connection level security credentials (e.g., TLS/SSL). | ||
210 | func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { | ||
211 | return func(o *dialOptions) { | ||
212 | o.copts.TransportCredentials = creds | ||
213 | } | ||
214 | } | ||
215 | |||
216 | // WithPerRPCCredentials returns a DialOption which sets | ||
217 | // credentials and places auth state on each outbound RPC. | ||
218 | func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { | ||
219 | return func(o *dialOptions) { | ||
220 | o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) | ||
221 | } | ||
222 | } | ||
223 | |||
224 | // WithTimeout returns a DialOption that configures a timeout for dialing a ClientConn | ||
225 | // initially. This is valid if and only if WithBlock() is present. | ||
226 | // Deprecated: use DialContext and context.WithTimeout instead. | ||
227 | func WithTimeout(d time.Duration) DialOption { | ||
228 | return func(o *dialOptions) { | ||
229 | o.timeout = d | ||
230 | } | ||
231 | } | ||
232 | |||
233 | // WithDialer returns a DialOption that specifies a function to use for dialing network addresses. | ||
234 | // If FailOnNonTempDialError() is set to true, and an error is returned by f, gRPC checks the error's | ||
235 | // Temporary() method to decide if it should try to reconnect to the network address. | ||
236 | func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { | ||
237 | return func(o *dialOptions) { | ||
238 | o.copts.Dialer = func(ctx context.Context, addr string) (net.Conn, error) { | ||
239 | if deadline, ok := ctx.Deadline(); ok { | ||
240 | return f(addr, deadline.Sub(time.Now())) | ||
241 | } | ||
242 | return f(addr, 0) | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | // WithStatsHandler returns a DialOption that specifies the stats handler | ||
248 | // for all the RPCs and underlying network connections in this ClientConn. | ||
249 | func WithStatsHandler(h stats.Handler) DialOption { | ||
250 | return func(o *dialOptions) { | ||
251 | o.copts.StatsHandler = h | ||
252 | } | ||
253 | } | ||
254 | |||
255 | // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on non-temporary dial errors. | ||
256 | // If f is true, and dialer returns a non-temporary error, gRPC will fail the connection to the network | ||
257 | // address and won't try to reconnect. | ||
258 | // The default value of FailOnNonTempDialError is false. | ||
259 | // This is an EXPERIMENTAL API. | ||
260 | func FailOnNonTempDialError(f bool) DialOption { | ||
261 | return func(o *dialOptions) { | ||
262 | o.copts.FailOnNonTempDialError = f | ||
263 | } | ||
264 | } | ||
265 | |||
266 | // WithUserAgent returns a DialOption that specifies a user agent string for all the RPCs. | ||
267 | func WithUserAgent(s string) DialOption { | ||
268 | return func(o *dialOptions) { | ||
269 | o.copts.UserAgent = s | ||
270 | } | ||
271 | } | ||
272 | |||
273 | // WithKeepaliveParams returns a DialOption that specifies keepalive paramaters for the client transport. | ||
274 | func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { | ||
275 | return func(o *dialOptions) { | ||
276 | o.copts.KeepaliveParams = kp | ||
277 | } | ||
278 | } | ||
279 | |||
280 | // WithUnaryInterceptor returns a DialOption that specifies the interceptor for unary RPCs. | ||
281 | func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { | ||
282 | return func(o *dialOptions) { | ||
283 | o.unaryInt = f | ||
284 | } | ||
285 | } | ||
286 | |||
287 | // WithStreamInterceptor returns a DialOption that specifies the interceptor for streaming RPCs. | ||
288 | func WithStreamInterceptor(f StreamClientInterceptor) DialOption { | ||
289 | return func(o *dialOptions) { | ||
290 | o.streamInt = f | ||
291 | } | ||
292 | } | ||
293 | |||
294 | // WithAuthority returns a DialOption that specifies the value to be used as | ||
295 | // the :authority pseudo-header. This value only works with WithInsecure and | ||
296 | // has no effect if TransportCredentials are present. | ||
297 | func WithAuthority(a string) DialOption { | ||
298 | return func(o *dialOptions) { | ||
299 | o.copts.Authority = a | ||
300 | } | ||
301 | } | ||
302 | |||
303 | // Dial creates a client connection to the given target. | 105 | // Dial creates a client connection to the given target. |
304 | func Dial(target string, opts ...DialOption) (*ClientConn, error) { | 106 | func Dial(target string, opts ...DialOption) (*ClientConn, error) { |
305 | return DialContext(context.Background(), target, opts...) | 107 | return DialContext(context.Background(), target, opts...) |
306 | } | 108 | } |
307 | 109 | ||
308 | // DialContext creates a client connection to the given target. ctx can be used to | 110 | // DialContext creates a client connection to the given target. By default, it's |
309 | // cancel or expire the pending connection. Once this function returns, the | 111 | // a non-blocking dial (the function won't wait for connections to be |
310 | // cancellation and expiration of ctx will be noop. Users should call ClientConn.Close | 112 | // established, and connecting happens in the background). To make it a blocking |
311 | // to terminate all the pending operations after this function returns. | 113 | // dial, use WithBlock() dial option. |
114 | // | ||
115 | // In the non-blocking case, the ctx does not act against the connection. It | ||
116 | // only controls the setup steps. | ||
117 | // | ||
118 | // In the blocking case, ctx can be used to cancel or expire the pending | ||
119 | // connection. Once this function returns, the cancellation and expiration of | ||
120 | // ctx will be noop. Users should call ClientConn.Close to terminate all the | ||
121 | // pending operations after this function returns. | ||
122 | // | ||
123 | // The target name syntax is defined in | ||
124 | // https://github.com/grpc/grpc/blob/master/doc/naming.md. | ||
125 | // e.g. to use dns resolver, a "dns:///" prefix should be applied to the target. | ||
312 | func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) { | 126 | func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) { |
313 | cc := &ClientConn{ | 127 | cc := &ClientConn{ |
314 | target: target, | 128 | target: target, |
315 | csMgr: &connectivityStateManager{}, | 129 | csMgr: &connectivityStateManager{}, |
316 | conns: make(map[Address]*addrConn), | 130 | conns: make(map[*addrConn]struct{}), |
317 | } | 131 | dopts: defaultDialOptions(), |
318 | cc.csEvltr = &connectivityStateEvaluator{csMgr: cc.csMgr} | 132 | blockingpicker: newPickerWrapper(), |
133 | czData: new(channelzData), | ||
134 | firstResolveEvent: grpcsync.NewEvent(), | ||
135 | } | ||
136 | cc.retryThrottler.Store((*retryThrottler)(nil)) | ||
319 | cc.ctx, cc.cancel = context.WithCancel(context.Background()) | 137 | cc.ctx, cc.cancel = context.WithCancel(context.Background()) |
320 | 138 | ||
321 | for _, opt := range opts { | 139 | for _, opt := range opts { |
322 | opt(&cc.dopts) | 140 | opt.apply(&cc.dopts) |
141 | } | ||
142 | |||
143 | if channelz.IsOn() { | ||
144 | if cc.dopts.channelzParentID != 0 { | ||
145 | cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target) | ||
146 | channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ | ||
147 | Desc: "Channel Created", | ||
148 | Severity: channelz.CtINFO, | ||
149 | Parent: &channelz.TraceEventDesc{ | ||
150 | Desc: fmt.Sprintf("Nested Channel(id:%d) created", cc.channelzID), | ||
151 | Severity: channelz.CtINFO, | ||
152 | }, | ||
153 | }) | ||
154 | } else { | ||
155 | cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, 0, target) | ||
156 | channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ | ||
157 | Desc: "Channel Created", | ||
158 | Severity: channelz.CtINFO, | ||
159 | }) | ||
160 | } | ||
161 | cc.csMgr.channelzID = cc.channelzID | ||
323 | } | 162 | } |
163 | |||
164 | if !cc.dopts.insecure { | ||
165 | if cc.dopts.copts.TransportCredentials == nil && cc.dopts.copts.CredsBundle == nil { | ||
166 | return nil, errNoTransportSecurity | ||
167 | } | ||
168 | if cc.dopts.copts.TransportCredentials != nil && cc.dopts.copts.CredsBundle != nil { | ||
169 | return nil, errTransportCredsAndBundle | ||
170 | } | ||
171 | } else { | ||
172 | if cc.dopts.copts.TransportCredentials != nil || cc.dopts.copts.CredsBundle != nil { | ||
173 | return nil, errCredentialsConflict | ||
174 | } | ||
175 | for _, cd := range cc.dopts.copts.PerRPCCredentials { | ||
176 | if cd.RequireTransportSecurity() { | ||
177 | return nil, errTransportCredentialsMissing | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
324 | cc.mkp = cc.dopts.copts.KeepaliveParams | 182 | cc.mkp = cc.dopts.copts.KeepaliveParams |
325 | 183 | ||
326 | if cc.dopts.copts.Dialer == nil { | 184 | if cc.dopts.copts.Dialer == nil { |
327 | cc.dopts.copts.Dialer = newProxyDialer( | 185 | cc.dopts.copts.Dialer = newProxyDialer( |
328 | func(ctx context.Context, addr string) (net.Conn, error) { | 186 | func(ctx context.Context, addr string) (net.Conn, error) { |
329 | return dialContext(ctx, "tcp", addr) | 187 | network, addr := parseDialTarget(addr) |
188 | return (&net.Dialer{}).DialContext(ctx, network, addr) | ||
330 | }, | 189 | }, |
331 | ) | 190 | ) |
332 | } | 191 | } |
@@ -367,66 +226,41 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * | |||
367 | default: | 226 | default: |
368 | } | 227 | } |
369 | } | 228 | } |
370 | // Set defaults. | ||
371 | if cc.dopts.codec == nil { | ||
372 | cc.dopts.codec = protoCodec{} | ||
373 | } | ||
374 | if cc.dopts.bs == nil { | 229 | if cc.dopts.bs == nil { |
375 | cc.dopts.bs = DefaultBackoffConfig | 230 | cc.dopts.bs = backoff.Exponential{ |
231 | MaxDelay: DefaultBackoffConfig.MaxDelay, | ||
232 | } | ||
233 | } | ||
234 | if cc.dopts.resolverBuilder == nil { | ||
235 | // Only try to parse target when resolver builder is not already set. | ||
236 | cc.parsedTarget = parseTarget(cc.target) | ||
237 | grpclog.Infof("parsed scheme: %q", cc.parsedTarget.Scheme) | ||
238 | cc.dopts.resolverBuilder = resolver.Get(cc.parsedTarget.Scheme) | ||
239 | if cc.dopts.resolverBuilder == nil { | ||
240 | // If resolver builder is still nil, the parse target's scheme is | ||
241 | // not registered. Fallback to default resolver and set Endpoint to | ||
242 | // the original unparsed target. | ||
243 | grpclog.Infof("scheme %q not registered, fallback to default scheme", cc.parsedTarget.Scheme) | ||
244 | cc.parsedTarget = resolver.Target{ | ||
245 | Scheme: resolver.GetDefaultScheme(), | ||
246 | Endpoint: target, | ||
247 | } | ||
248 | cc.dopts.resolverBuilder = resolver.Get(cc.parsedTarget.Scheme) | ||
249 | } | ||
250 | } else { | ||
251 | cc.parsedTarget = resolver.Target{Endpoint: target} | ||
376 | } | 252 | } |
377 | creds := cc.dopts.copts.TransportCredentials | 253 | creds := cc.dopts.copts.TransportCredentials |
378 | if creds != nil && creds.Info().ServerName != "" { | 254 | if creds != nil && creds.Info().ServerName != "" { |
379 | cc.authority = creds.Info().ServerName | 255 | cc.authority = creds.Info().ServerName |
380 | } else if cc.dopts.insecure && cc.dopts.copts.Authority != "" { | 256 | } else if cc.dopts.insecure && cc.dopts.authority != "" { |
381 | cc.authority = cc.dopts.copts.Authority | 257 | cc.authority = cc.dopts.authority |
382 | } else { | 258 | } else { |
383 | cc.authority = target | 259 | // Use endpoint from "scheme://authority/endpoint" as the default |
384 | } | 260 | // authority for ClientConn. |
385 | waitC := make(chan error, 1) | 261 | cc.authority = cc.parsedTarget.Endpoint |
386 | go func() { | ||
387 | defer close(waitC) | ||
388 | if cc.dopts.balancer == nil && cc.sc.LB != nil { | ||
389 | cc.dopts.balancer = cc.sc.LB | ||
390 | } | ||
391 | if cc.dopts.balancer != nil { | ||
392 | var credsClone credentials.TransportCredentials | ||
393 | if creds != nil { | ||
394 | credsClone = creds.Clone() | ||
395 | } | ||
396 | config := BalancerConfig{ | ||
397 | DialCreds: credsClone, | ||
398 | Dialer: cc.dopts.copts.Dialer, | ||
399 | } | ||
400 | if err := cc.dopts.balancer.Start(target, config); err != nil { | ||
401 | waitC <- err | ||
402 | return | ||
403 | } | ||
404 | ch := cc.dopts.balancer.Notify() | ||
405 | if ch != nil { | ||
406 | if cc.dopts.block { | ||
407 | doneChan := make(chan struct{}) | ||
408 | go cc.lbWatcher(doneChan) | ||
409 | <-doneChan | ||
410 | } else { | ||
411 | go cc.lbWatcher(nil) | ||
412 | } | ||
413 | return | ||
414 | } | ||
415 | } | ||
416 | // No balancer, or no resolver within the balancer. Connect directly. | ||
417 | if err := cc.resetAddrConn(Address{Addr: target}, cc.dopts.block, nil); err != nil { | ||
418 | waitC <- err | ||
419 | return | ||
420 | } | ||
421 | }() | ||
422 | select { | ||
423 | case <-ctx.Done(): | ||
424 | return nil, ctx.Err() | ||
425 | case err := <-waitC: | ||
426 | if err != nil { | ||
427 | return nil, err | ||
428 | } | ||
429 | } | 262 | } |
263 | |||
430 | if cc.dopts.scChan != nil && !scSet { | 264 | if cc.dopts.scChan != nil && !scSet { |
431 | // Blocking wait for the initial service config. | 265 | // Blocking wait for the initial service config. |
432 | select { | 266 | select { |
@@ -442,55 +276,50 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * | |||
442 | go cc.scWatcher() | 276 | go cc.scWatcher() |
443 | } | 277 | } |
444 | 278 | ||
445 | return cc, nil | 279 | var credsClone credentials.TransportCredentials |
446 | } | 280 | if creds := cc.dopts.copts.TransportCredentials; creds != nil { |
281 | credsClone = creds.Clone() | ||
282 | } | ||
283 | cc.balancerBuildOpts = balancer.BuildOptions{ | ||
284 | DialCreds: credsClone, | ||
285 | CredsBundle: cc.dopts.copts.CredsBundle, | ||
286 | Dialer: cc.dopts.copts.Dialer, | ||
287 | ChannelzParentID: cc.channelzID, | ||
288 | } | ||
447 | 289 | ||
448 | // connectivityStateEvaluator gets updated by addrConns when their | 290 | // Build the resolver. |
449 | // states transition, based on which it evaluates the state of | 291 | rWrapper, err := newCCResolverWrapper(cc) |
450 | // ClientConn. | 292 | if err != nil { |
451 | // Note: This code will eventually sit in the balancer in the new design. | 293 | return nil, fmt.Errorf("failed to build resolver: %v", err) |
452 | type connectivityStateEvaluator struct { | 294 | } |
453 | csMgr *connectivityStateManager | ||
454 | mu sync.Mutex | ||
455 | numReady uint64 // Number of addrConns in ready state. | ||
456 | numConnecting uint64 // Number of addrConns in connecting state. | ||
457 | numTransientFailure uint64 // Number of addrConns in transientFailure. | ||
458 | } | ||
459 | 295 | ||
460 | // recordTransition records state change happening in every addrConn and based on | 296 | cc.mu.Lock() |
461 | // that it evaluates what state the ClientConn is in. | 297 | cc.resolverWrapper = rWrapper |
462 | // It can only transition between connectivity.Ready, connectivity.Connecting and connectivity.TransientFailure. Other states, | 298 | cc.mu.Unlock() |
463 | // Idle and connectivity.Shutdown are transitioned into by ClientConn; in the begining of the connection | 299 | // A blocking dial blocks until the clientConn is ready. |
464 | // before any addrConn is created ClientConn is in idle state. In the end when ClientConn | 300 | if cc.dopts.block { |
465 | // closes it is in connectivity.Shutdown state. | 301 | for { |
466 | // TODO Note that in later releases, a ClientConn with no activity will be put into an Idle state. | 302 | s := cc.GetState() |
467 | func (cse *connectivityStateEvaluator) recordTransition(oldState, newState connectivity.State) { | 303 | if s == connectivity.Ready { |
468 | cse.mu.Lock() | 304 | break |
469 | defer cse.mu.Unlock() | 305 | } else if cc.dopts.copts.FailOnNonTempDialError && s == connectivity.TransientFailure { |
470 | 306 | if err = cc.blockingpicker.connectionError(); err != nil { | |
471 | // Update counters. | 307 | terr, ok := err.(interface { |
472 | for idx, state := range []connectivity.State{oldState, newState} { | 308 | Temporary() bool |
473 | updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new. | 309 | }) |
474 | switch state { | 310 | if ok && !terr.Temporary() { |
475 | case connectivity.Ready: | 311 | return nil, err |
476 | cse.numReady += updateVal | 312 | } |
477 | case connectivity.Connecting: | 313 | } |
478 | cse.numConnecting += updateVal | 314 | } |
479 | case connectivity.TransientFailure: | 315 | if !cc.WaitForStateChange(ctx, s) { |
480 | cse.numTransientFailure += updateVal | 316 | // ctx got timeout or canceled. |
317 | return nil, ctx.Err() | ||
318 | } | ||
481 | } | 319 | } |
482 | } | 320 | } |
483 | 321 | ||
484 | // Evaluate. | 322 | return cc, nil |
485 | if cse.numReady > 0 { | ||
486 | cse.csMgr.updateState(connectivity.Ready) | ||
487 | return | ||
488 | } | ||
489 | if cse.numConnecting > 0 { | ||
490 | cse.csMgr.updateState(connectivity.Connecting) | ||
491 | return | ||
492 | } | ||
493 | cse.csMgr.updateState(connectivity.TransientFailure) | ||
494 | } | 323 | } |
495 | 324 | ||
496 | // connectivityStateManager keeps the connectivity.State of ClientConn. | 325 | // connectivityStateManager keeps the connectivity.State of ClientConn. |
@@ -499,6 +328,7 @@ type connectivityStateManager struct { | |||
499 | mu sync.Mutex | 328 | mu sync.Mutex |
500 | state connectivity.State | 329 | state connectivity.State |
501 | notifyChan chan struct{} | 330 | notifyChan chan struct{} |
331 | channelzID int64 | ||
502 | } | 332 | } |
503 | 333 | ||
504 | // updateState updates the connectivity.State of ClientConn. | 334 | // updateState updates the connectivity.State of ClientConn. |
@@ -514,6 +344,12 @@ func (csm *connectivityStateManager) updateState(state connectivity.State) { | |||
514 | return | 344 | return |
515 | } | 345 | } |
516 | csm.state = state | 346 | csm.state = state |
347 | if channelz.IsOn() { | ||
348 | channelz.AddTraceEvent(csm.channelzID, &channelz.TraceEventDesc{ | ||
349 | Desc: fmt.Sprintf("Channel Connectivity change to %v", state), | ||
350 | Severity: channelz.CtINFO, | ||
351 | }) | ||
352 | } | ||
517 | if csm.notifyChan != nil { | 353 | if csm.notifyChan != nil { |
518 | // There are other goroutines waiting on this channel. | 354 | // There are other goroutines waiting on this channel. |
519 | close(csm.notifyChan) | 355 | close(csm.notifyChan) |
@@ -541,17 +377,32 @@ type ClientConn struct { | |||
541 | ctx context.Context | 377 | ctx context.Context |
542 | cancel context.CancelFunc | 378 | cancel context.CancelFunc |
543 | 379 | ||
544 | target string | 380 | target string |
545 | authority string | 381 | parsedTarget resolver.Target |
546 | dopts dialOptions | 382 | authority string |
547 | csMgr *connectivityStateManager | 383 | dopts dialOptions |
548 | csEvltr *connectivityStateEvaluator // This will eventually be part of balancer. | 384 | csMgr *connectivityStateManager |
549 | 385 | ||
550 | mu sync.RWMutex | 386 | balancerBuildOpts balancer.BuildOptions |
551 | sc ServiceConfig | 387 | blockingpicker *pickerWrapper |
552 | conns map[Address]*addrConn | 388 | |
389 | mu sync.RWMutex | ||
390 | resolverWrapper *ccResolverWrapper | ||
391 | sc ServiceConfig | ||
392 | scRaw string | ||
393 | conns map[*addrConn]struct{} | ||
553 | // Keepalive parameter can be updated if a GoAway is received. | 394 | // Keepalive parameter can be updated if a GoAway is received. |
554 | mkp keepalive.ClientParameters | 395 | mkp keepalive.ClientParameters |
396 | curBalancerName string | ||
397 | preBalancerName string // previous balancer name. | ||
398 | curAddresses []resolver.Address | ||
399 | balancerWrapper *ccBalancerWrapper | ||
400 | retryThrottler atomic.Value | ||
401 | |||
402 | firstResolveEvent *grpcsync.Event | ||
403 | |||
404 | channelzID int64 // channelz unique identification number | ||
405 | czData *channelzData | ||
555 | } | 406 | } |
556 | 407 | ||
557 | // WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or | 408 | // WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or |
@@ -576,65 +427,6 @@ func (cc *ClientConn) GetState() connectivity.State { | |||
576 | return cc.csMgr.getState() | 427 | return cc.csMgr.getState() |
577 | } | 428 | } |
578 | 429 | ||
579 | // lbWatcher watches the Notify channel of the balancer in cc and manages | ||
580 | // connections accordingly. If doneChan is not nil, it is closed after the | ||
581 | // first successfull connection is made. | ||
582 | func (cc *ClientConn) lbWatcher(doneChan chan struct{}) { | ||
583 | defer func() { | ||
584 | // In case channel from cc.dopts.balancer.Notify() gets closed before a | ||
585 | // successful connection gets established, don't forget to notify the | ||
586 | // caller. | ||
587 | if doneChan != nil { | ||
588 | close(doneChan) | ||
589 | } | ||
590 | }() | ||
591 | |||
592 | for addrs := range cc.dopts.balancer.Notify() { | ||
593 | var ( | ||
594 | add []Address // Addresses need to setup connections. | ||
595 | del []*addrConn // Connections need to tear down. | ||
596 | ) | ||
597 | cc.mu.Lock() | ||
598 | for _, a := range addrs { | ||
599 | if _, ok := cc.conns[a]; !ok { | ||
600 | add = append(add, a) | ||
601 | } | ||
602 | } | ||
603 | for k, c := range cc.conns { | ||
604 | var keep bool | ||
605 | for _, a := range addrs { | ||
606 | if k == a { | ||
607 | keep = true | ||
608 | break | ||
609 | } | ||
610 | } | ||
611 | if !keep { | ||
612 | del = append(del, c) | ||
613 | delete(cc.conns, c.addr) | ||
614 | } | ||
615 | } | ||
616 | cc.mu.Unlock() | ||
617 | for _, a := range add { | ||
618 | var err error | ||
619 | if doneChan != nil { | ||
620 | err = cc.resetAddrConn(a, true, nil) | ||
621 | if err == nil { | ||
622 | close(doneChan) | ||
623 | doneChan = nil | ||
624 | } | ||
625 | } else { | ||
626 | err = cc.resetAddrConn(a, false, nil) | ||
627 | } | ||
628 | if err != nil { | ||
629 | grpclog.Warningf("Error creating connection to %v. Err: %v", a, err) | ||
630 | } | ||
631 | } | ||
632 | for _, c := range del { | ||
633 | c.tearDown(errConnDrain) | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | |||
638 | func (cc *ClientConn) scWatcher() { | 430 | func (cc *ClientConn) scWatcher() { |
639 | for { | 431 | for { |
640 | select { | 432 | select { |
@@ -646,6 +438,7 @@ func (cc *ClientConn) scWatcher() { | |||
646 | // TODO: load balance policy runtime change is ignored. | 438 | // TODO: load balance policy runtime change is ignored. |
647 | // We may revist this decision in the future. | 439 | // We may revist this decision in the future. |
648 | cc.sc = sc | 440 | cc.sc = sc |
441 | cc.scRaw = "" | ||
649 | cc.mu.Unlock() | 442 | cc.mu.Unlock() |
650 | case <-cc.ctx.Done(): | 443 | case <-cc.ctx.Done(): |
651 | return | 444 | return |
@@ -653,99 +446,287 @@ func (cc *ClientConn) scWatcher() { | |||
653 | } | 446 | } |
654 | } | 447 | } |
655 | 448 | ||
656 | // resetAddrConn creates an addrConn for addr and adds it to cc.conns. | 449 | // waitForResolvedAddrs blocks until the resolver has provided addresses or the |
657 | // If there is an old addrConn for addr, it will be torn down, using tearDownErr as the reason. | 450 | // context expires. Returns nil unless the context expires first; otherwise |
658 | // If tearDownErr is nil, errConnDrain will be used instead. | 451 | // returns a status error based on the context. |
659 | // | 452 | func (cc *ClientConn) waitForResolvedAddrs(ctx context.Context) error { |
660 | // We should never need to replace an addrConn with a new one. This function is only used | 453 | // This is on the RPC path, so we use a fast path to avoid the |
661 | // as newAddrConn to create new addrConn. | 454 | // more-expensive "select" below after the resolver has returned once. |
662 | // TODO rename this function and clean up the code. | 455 | if cc.firstResolveEvent.HasFired() { |
663 | func (cc *ClientConn) resetAddrConn(addr Address, block bool, tearDownErr error) error { | 456 | return nil |
664 | ac := &addrConn{ | ||
665 | cc: cc, | ||
666 | addr: addr, | ||
667 | dopts: cc.dopts, | ||
668 | } | 457 | } |
669 | ac.ctx, ac.cancel = context.WithCancel(cc.ctx) | 458 | select { |
670 | ac.csEvltr = cc.csEvltr | 459 | case <-cc.firstResolveEvent.Done(): |
671 | if EnableTracing { | 460 | return nil |
672 | ac.events = trace.NewEventLog("grpc.ClientConn", ac.addr.Addr) | 461 | case <-ctx.Done(): |
462 | return status.FromContextError(ctx.Err()).Err() | ||
463 | case <-cc.ctx.Done(): | ||
464 | return ErrClientConnClosing | ||
673 | } | 465 | } |
674 | if !ac.dopts.insecure { | 466 | } |
675 | if ac.dopts.copts.TransportCredentials == nil { | 467 | |
676 | return errNoTransportSecurity | 468 | func (cc *ClientConn) handleResolvedAddrs(addrs []resolver.Address, err error) { |
677 | } | 469 | cc.mu.Lock() |
678 | } else { | 470 | defer cc.mu.Unlock() |
679 | if ac.dopts.copts.TransportCredentials != nil { | 471 | if cc.conns == nil { |
680 | return errCredentialsConflict | 472 | // cc was closed. |
473 | return | ||
474 | } | ||
475 | |||
476 | if reflect.DeepEqual(cc.curAddresses, addrs) { | ||
477 | return | ||
478 | } | ||
479 | |||
480 | cc.curAddresses = addrs | ||
481 | cc.firstResolveEvent.Fire() | ||
482 | |||
483 | if cc.dopts.balancerBuilder == nil { | ||
484 | // Only look at balancer types and switch balancer if balancer dial | ||
485 | // option is not set. | ||
486 | var isGRPCLB bool | ||
487 | for _, a := range addrs { | ||
488 | if a.Type == resolver.GRPCLB { | ||
489 | isGRPCLB = true | ||
490 | break | ||
491 | } | ||
681 | } | 492 | } |
682 | for _, cd := range ac.dopts.copts.PerRPCCredentials { | 493 | var newBalancerName string |
683 | if cd.RequireTransportSecurity() { | 494 | if isGRPCLB { |
684 | return errTransportCredentialsMissing | 495 | newBalancerName = grpclbName |
496 | } else { | ||
497 | // Address list doesn't contain grpclb address. Try to pick a | ||
498 | // non-grpclb balancer. | ||
499 | newBalancerName = cc.curBalancerName | ||
500 | // If current balancer is grpclb, switch to the previous one. | ||
501 | if newBalancerName == grpclbName { | ||
502 | newBalancerName = cc.preBalancerName | ||
503 | } | ||
504 | // The following could be true in two cases: | ||
505 | // - the first time handling resolved addresses | ||
506 | // (curBalancerName="") | ||
507 | // - the first time handling non-grpclb addresses | ||
508 | // (curBalancerName="grpclb", preBalancerName="") | ||
509 | if newBalancerName == "" { | ||
510 | newBalancerName = PickFirstBalancerName | ||
685 | } | 511 | } |
686 | } | 512 | } |
513 | cc.switchBalancer(newBalancerName) | ||
514 | } else if cc.balancerWrapper == nil { | ||
515 | // Balancer dial option was set, and this is the first time handling | ||
516 | // resolved addresses. Build a balancer with dopts.balancerBuilder. | ||
517 | cc.balancerWrapper = newCCBalancerWrapper(cc, cc.dopts.balancerBuilder, cc.balancerBuildOpts) | ||
687 | } | 518 | } |
519 | |||
520 | cc.balancerWrapper.handleResolvedAddrs(addrs, nil) | ||
521 | } | ||
522 | |||
523 | // switchBalancer starts the switching from current balancer to the balancer | ||
524 | // with the given name. | ||
525 | // | ||
526 | // It will NOT send the current address list to the new balancer. If needed, | ||
527 | // caller of this function should send address list to the new balancer after | ||
528 | // this function returns. | ||
529 | // | ||
530 | // Caller must hold cc.mu. | ||
531 | func (cc *ClientConn) switchBalancer(name string) { | ||
532 | if cc.conns == nil { | ||
533 | return | ||
534 | } | ||
535 | |||
536 | if strings.ToLower(cc.curBalancerName) == strings.ToLower(name) { | ||
537 | return | ||
538 | } | ||
539 | |||
540 | grpclog.Infof("ClientConn switching balancer to %q", name) | ||
541 | if cc.dopts.balancerBuilder != nil { | ||
542 | grpclog.Infoln("ignoring balancer switching: Balancer DialOption used instead") | ||
543 | return | ||
544 | } | ||
545 | // TODO(bar switching) change this to two steps: drain and close. | ||
546 | // Keep track of sc in wrapper. | ||
547 | if cc.balancerWrapper != nil { | ||
548 | cc.balancerWrapper.close() | ||
549 | } | ||
550 | |||
551 | builder := balancer.Get(name) | ||
552 | // TODO(yuxuanli): If user send a service config that does not contain a valid balancer name, should | ||
553 | // we reuse previous one? | ||
554 | if channelz.IsOn() { | ||
555 | if builder == nil { | ||
556 | channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ | ||
557 | Desc: fmt.Sprintf("Channel switches to new LB policy %q due to fallback from invalid balancer name", PickFirstBalancerName), | ||
558 | Severity: channelz.CtWarning, | ||
559 | }) | ||
560 | } else { | ||
561 | channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ | ||
562 | Desc: fmt.Sprintf("Channel switches to new LB policy %q", name), | ||
563 | Severity: channelz.CtINFO, | ||
564 | }) | ||
565 | } | ||
566 | } | ||
567 | if builder == nil { | ||
568 | grpclog.Infof("failed to get balancer builder for: %v, using pick_first instead", name) | ||
569 | builder = newPickfirstBuilder() | ||
570 | } | ||
571 | |||
572 | cc.preBalancerName = cc.curBalancerName | ||
573 | cc.curBalancerName = builder.Name() | ||
574 | cc.balancerWrapper = newCCBalancerWrapper(cc, builder, cc.balancerBuildOpts) | ||
575 | } | ||
576 | |||
577 | func (cc *ClientConn) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { | ||
578 | cc.mu.Lock() | ||
579 | if cc.conns == nil { | ||
580 | cc.mu.Unlock() | ||
581 | return | ||
582 | } | ||
583 | // TODO(bar switching) send updates to all balancer wrappers when balancer | ||
584 | // gracefully switching is supported. | ||
585 | cc.balancerWrapper.handleSubConnStateChange(sc, s) | ||
586 | cc.mu.Unlock() | ||
587 | } | ||
588 | |||
589 | // newAddrConn creates an addrConn for addrs and adds it to cc.conns. | ||
590 | // | ||
591 | // Caller needs to make sure len(addrs) > 0. | ||
592 | func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (*addrConn, error) { | ||
593 | ac := &addrConn{ | ||
594 | cc: cc, | ||
595 | addrs: addrs, | ||
596 | scopts: opts, | ||
597 | dopts: cc.dopts, | ||
598 | czData: new(channelzData), | ||
599 | resetBackoff: make(chan struct{}), | ||
600 | } | ||
601 | ac.ctx, ac.cancel = context.WithCancel(cc.ctx) | ||
688 | // Track ac in cc. This needs to be done before any getTransport(...) is called. | 602 | // Track ac in cc. This needs to be done before any getTransport(...) is called. |
689 | cc.mu.Lock() | 603 | cc.mu.Lock() |
690 | if cc.conns == nil { | 604 | if cc.conns == nil { |
691 | cc.mu.Unlock() | 605 | cc.mu.Unlock() |
692 | return ErrClientConnClosing | 606 | return nil, ErrClientConnClosing |
607 | } | ||
608 | if channelz.IsOn() { | ||
609 | ac.channelzID = channelz.RegisterSubChannel(ac, cc.channelzID, "") | ||
610 | channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ | ||
611 | Desc: "Subchannel Created", | ||
612 | Severity: channelz.CtINFO, | ||
613 | Parent: &channelz.TraceEventDesc{ | ||
614 | Desc: fmt.Sprintf("Subchannel(id:%d) created", ac.channelzID), | ||
615 | Severity: channelz.CtINFO, | ||
616 | }, | ||
617 | }) | ||
693 | } | 618 | } |
694 | stale := cc.conns[ac.addr] | 619 | cc.conns[ac] = struct{}{} |
695 | cc.conns[ac.addr] = ac | ||
696 | cc.mu.Unlock() | 620 | cc.mu.Unlock() |
697 | if stale != nil { | 621 | return ac, nil |
698 | // There is an addrConn alive on ac.addr already. This could be due to | 622 | } |
699 | // a buggy Balancer that reports duplicated Addresses. | 623 | |
700 | if tearDownErr == nil { | 624 | // removeAddrConn removes the addrConn in the subConn from clientConn. |
701 | // tearDownErr is nil if resetAddrConn is called by | 625 | // It also tears down the ac with the given error. |
702 | // 1) Dial | 626 | func (cc *ClientConn) removeAddrConn(ac *addrConn, err error) { |
703 | // 2) lbWatcher | 627 | cc.mu.Lock() |
704 | // In both cases, the stale ac should drain, not close. | 628 | if cc.conns == nil { |
705 | stale.tearDown(errConnDrain) | 629 | cc.mu.Unlock() |
706 | } else { | 630 | return |
707 | stale.tearDown(tearDownErr) | ||
708 | } | ||
709 | } | 631 | } |
710 | if block { | 632 | delete(cc.conns, ac) |
711 | if err := ac.resetTransport(false); err != nil { | 633 | cc.mu.Unlock() |
712 | if err != errConnClosing { | 634 | ac.tearDown(err) |
713 | // Tear down ac and delete it from cc.conns. | 635 | } |
714 | cc.mu.Lock() | 636 | |
715 | delete(cc.conns, ac.addr) | 637 | func (cc *ClientConn) channelzMetric() *channelz.ChannelInternalMetric { |
716 | cc.mu.Unlock() | 638 | return &channelz.ChannelInternalMetric{ |
717 | ac.tearDown(err) | 639 | State: cc.GetState(), |
718 | } | 640 | Target: cc.target, |
719 | if e, ok := err.(transport.ConnectionError); ok && !e.Temporary() { | 641 | CallsStarted: atomic.LoadInt64(&cc.czData.callsStarted), |
720 | return e.Origin() | 642 | CallsSucceeded: atomic.LoadInt64(&cc.czData.callsSucceeded), |
721 | } | 643 | CallsFailed: atomic.LoadInt64(&cc.czData.callsFailed), |
722 | return err | 644 | LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&cc.czData.lastCallStartedTime)), |
723 | } | 645 | } |
724 | // Start to monitor the error status of transport. | 646 | } |
725 | go ac.transportMonitor() | 647 | |
726 | } else { | 648 | // Target returns the target string of the ClientConn. |
727 | // Start a goroutine connecting to the server asynchronously. | 649 | // This is an EXPERIMENTAL API. |
728 | go func() { | 650 | func (cc *ClientConn) Target() string { |
729 | if err := ac.resetTransport(false); err != nil { | 651 | return cc.target |
730 | grpclog.Warningf("Failed to dial %s: %v; please retry.", ac.addr.Addr, err) | 652 | } |
731 | if err != errConnClosing { | 653 | |
732 | // Keep this ac in cc.conns, to get the reason it's torn down. | 654 | func (cc *ClientConn) incrCallsStarted() { |
733 | ac.tearDown(err) | 655 | atomic.AddInt64(&cc.czData.callsStarted, 1) |
734 | } | 656 | atomic.StoreInt64(&cc.czData.lastCallStartedTime, time.Now().UnixNano()) |
735 | return | 657 | } |
736 | } | 658 | |
737 | ac.transportMonitor() | 659 | func (cc *ClientConn) incrCallsSucceeded() { |
738 | }() | 660 | atomic.AddInt64(&cc.czData.callsSucceeded, 1) |
661 | } | ||
662 | |||
663 | func (cc *ClientConn) incrCallsFailed() { | ||
664 | atomic.AddInt64(&cc.czData.callsFailed, 1) | ||
665 | } | ||
666 | |||
667 | // connect starts creating a transport. | ||
668 | // It does nothing if the ac is not IDLE. | ||
669 | // TODO(bar) Move this to the addrConn section. | ||
670 | func (ac *addrConn) connect() error { | ||
671 | ac.mu.Lock() | ||
672 | if ac.state == connectivity.Shutdown { | ||
673 | ac.mu.Unlock() | ||
674 | return errConnClosing | ||
675 | } | ||
676 | if ac.state != connectivity.Idle { | ||
677 | ac.mu.Unlock() | ||
678 | return nil | ||
739 | } | 679 | } |
680 | ac.updateConnectivityState(connectivity.Connecting) | ||
681 | ac.mu.Unlock() | ||
682 | |||
683 | // Start a goroutine connecting to the server asynchronously. | ||
684 | go ac.resetTransport() | ||
740 | return nil | 685 | return nil |
741 | } | 686 | } |
742 | 687 | ||
688 | // tryUpdateAddrs tries to update ac.addrs with the new addresses list. | ||
689 | // | ||
690 | // It checks whether current connected address of ac is in the new addrs list. | ||
691 | // - If true, it updates ac.addrs and returns true. The ac will keep using | ||
692 | // the existing connection. | ||
693 | // - If false, it does nothing and returns false. | ||
694 | func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { | ||
695 | ac.mu.Lock() | ||
696 | defer ac.mu.Unlock() | ||
697 | grpclog.Infof("addrConn: tryUpdateAddrs curAddr: %v, addrs: %v", ac.curAddr, addrs) | ||
698 | if ac.state == connectivity.Shutdown { | ||
699 | ac.addrs = addrs | ||
700 | return true | ||
701 | } | ||
702 | |||
703 | // Unless we're busy reconnecting already, let's reconnect from the top of | ||
704 | // the list. | ||
705 | if ac.state != connectivity.Ready { | ||
706 | return false | ||
707 | } | ||
708 | |||
709 | var curAddrFound bool | ||
710 | for _, a := range addrs { | ||
711 | if reflect.DeepEqual(ac.curAddr, a) { | ||
712 | curAddrFound = true | ||
713 | break | ||
714 | } | ||
715 | } | ||
716 | grpclog.Infof("addrConn: tryUpdateAddrs curAddrFound: %v", curAddrFound) | ||
717 | if curAddrFound { | ||
718 | ac.addrs = addrs | ||
719 | } | ||
720 | |||
721 | return curAddrFound | ||
722 | } | ||
723 | |||
743 | // GetMethodConfig gets the method config of the input method. | 724 | // GetMethodConfig gets the method config of the input method. |
744 | // If there's an exact match for input method (i.e. /service/method), we return | 725 | // If there's an exact match for input method (i.e. /service/method), we return |
745 | // the corresponding MethodConfig. | 726 | // the corresponding MethodConfig. |
746 | // If there isn't an exact match for the input method, we look for the default config | 727 | // If there isn't an exact match for the input method, we look for the default config |
747 | // under the service (i.e /service/). If there is a default MethodConfig for | 728 | // under the service (i.e /service/). If there is a default MethodConfig for |
748 | // the serivce, we return it. | 729 | // the service, we return it. |
749 | // Otherwise, we return an empty MethodConfig. | 730 | // Otherwise, we return an empty MethodConfig. |
750 | func (cc *ClientConn) GetMethodConfig(method string) MethodConfig { | 731 | func (cc *ClientConn) GetMethodConfig(method string) MethodConfig { |
751 | // TODO: Avoid the locking here. | 732 | // TODO: Avoid the locking here. |
@@ -754,68 +735,122 @@ func (cc *ClientConn) GetMethodConfig(method string) MethodConfig { | |||
754 | m, ok := cc.sc.Methods[method] | 735 | m, ok := cc.sc.Methods[method] |
755 | if !ok { | 736 | if !ok { |
756 | i := strings.LastIndex(method, "/") | 737 | i := strings.LastIndex(method, "/") |
757 | m, _ = cc.sc.Methods[method[:i+1]] | 738 | m = cc.sc.Methods[method[:i+1]] |
758 | } | 739 | } |
759 | return m | 740 | return m |
760 | } | 741 | } |
761 | 742 | ||
762 | func (cc *ClientConn) getTransport(ctx context.Context, opts BalancerGetOptions) (transport.ClientTransport, func(), error) { | 743 | func (cc *ClientConn) healthCheckConfig() *healthCheckConfig { |
763 | var ( | 744 | cc.mu.RLock() |
764 | ac *addrConn | 745 | defer cc.mu.RUnlock() |
765 | ok bool | 746 | return cc.sc.healthCheckConfig |
766 | put func() | 747 | } |
767 | ) | 748 | |
768 | if cc.dopts.balancer == nil { | 749 | func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, func(balancer.DoneInfo), error) { |
769 | // If balancer is nil, there should be only one addrConn available. | 750 | hdr, _ := metadata.FromOutgoingContext(ctx) |
770 | cc.mu.RLock() | 751 | t, done, err := cc.blockingpicker.pick(ctx, failfast, balancer.PickOptions{ |
771 | if cc.conns == nil { | 752 | FullMethodName: method, |
772 | cc.mu.RUnlock() | 753 | Header: hdr, |
773 | return nil, nil, toRPCErr(ErrClientConnClosing) | 754 | }) |
774 | } | 755 | if err != nil { |
775 | for _, ac = range cc.conns { | 756 | return nil, nil, toRPCErr(err) |
776 | // Break after the first iteration to get the first addrConn. | 757 | } |
777 | ok = true | 758 | return t, done, nil |
778 | break | 759 | } |
760 | |||
761 | // handleServiceConfig parses the service config string in JSON format to Go native | ||
762 | // struct ServiceConfig, and store both the struct and the JSON string in ClientConn. | ||
763 | func (cc *ClientConn) handleServiceConfig(js string) error { | ||
764 | if cc.dopts.disableServiceConfig { | ||
765 | return nil | ||
766 | } | ||
767 | if cc.scRaw == js { | ||
768 | return nil | ||
769 | } | ||
770 | if channelz.IsOn() { | ||
771 | channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ | ||
772 | // The special formatting of \"%s\" instead of %q is to provide nice printing of service config | ||
773 | // for human consumption. | ||
774 | Desc: fmt.Sprintf("Channel has a new service config \"%s\"", js), | ||
775 | Severity: channelz.CtINFO, | ||
776 | }) | ||
777 | } | ||
778 | sc, err := parseServiceConfig(js) | ||
779 | if err != nil { | ||
780 | return err | ||
781 | } | ||
782 | cc.mu.Lock() | ||
783 | // Check if the ClientConn is already closed. Some fields (e.g. | ||
784 | // balancerWrapper) are set to nil when closing the ClientConn, and could | ||
785 | // cause nil pointer panic if we don't have this check. | ||
786 | if cc.conns == nil { | ||
787 | cc.mu.Unlock() | ||
788 | return nil | ||
789 | } | ||
790 | cc.scRaw = js | ||
791 | cc.sc = sc | ||
792 | |||
793 | if sc.retryThrottling != nil { | ||
794 | newThrottler := &retryThrottler{ | ||
795 | tokens: sc.retryThrottling.MaxTokens, | ||
796 | max: sc.retryThrottling.MaxTokens, | ||
797 | thresh: sc.retryThrottling.MaxTokens / 2, | ||
798 | ratio: sc.retryThrottling.TokenRatio, | ||
779 | } | 799 | } |
780 | cc.mu.RUnlock() | 800 | cc.retryThrottler.Store(newThrottler) |
781 | } else { | 801 | } else { |
782 | var ( | 802 | cc.retryThrottler.Store((*retryThrottler)(nil)) |
783 | addr Address | ||
784 | err error | ||
785 | ) | ||
786 | addr, put, err = cc.dopts.balancer.Get(ctx, opts) | ||
787 | if err != nil { | ||
788 | return nil, nil, toRPCErr(err) | ||
789 | } | ||
790 | cc.mu.RLock() | ||
791 | if cc.conns == nil { | ||
792 | cc.mu.RUnlock() | ||
793 | return nil, nil, toRPCErr(ErrClientConnClosing) | ||
794 | } | ||
795 | ac, ok = cc.conns[addr] | ||
796 | cc.mu.RUnlock() | ||
797 | } | 803 | } |
798 | if !ok { | 804 | |
799 | if put != nil { | 805 | if sc.LB != nil && *sc.LB != grpclbName { // "grpclb" is not a valid balancer option in service config. |
800 | updateRPCInfoInContext(ctx, rpcInfo{bytesSent: false, bytesReceived: false}) | 806 | if cc.curBalancerName == grpclbName { |
801 | put() | 807 | // If current balancer is grpclb, there's at least one grpclb |
808 | // balancer address in the resolved list. Don't switch the balancer, | ||
809 | // but change the previous balancer name, so if a new resolved | ||
810 | // address list doesn't contain grpclb address, balancer will be | ||
811 | // switched to *sc.LB. | ||
812 | cc.preBalancerName = *sc.LB | ||
813 | } else { | ||
814 | cc.switchBalancer(*sc.LB) | ||
815 | cc.balancerWrapper.handleResolvedAddrs(cc.curAddresses, nil) | ||
802 | } | 816 | } |
803 | return nil, nil, errConnClosing | ||
804 | } | 817 | } |
805 | t, err := ac.wait(ctx, cc.dopts.balancer != nil, !opts.BlockingWait) | 818 | |
806 | if err != nil { | 819 | cc.mu.Unlock() |
807 | if put != nil { | 820 | return nil |
808 | updateRPCInfoInContext(ctx, rpcInfo{bytesSent: false, bytesReceived: false}) | 821 | } |
809 | put() | 822 | |
810 | } | 823 | func (cc *ClientConn) resolveNow(o resolver.ResolveNowOption) { |
811 | return nil, nil, err | 824 | cc.mu.RLock() |
825 | r := cc.resolverWrapper | ||
826 | cc.mu.RUnlock() | ||
827 | if r == nil { | ||
828 | return | ||
829 | } | ||
830 | go r.resolveNow(o) | ||
831 | } | ||
832 | |||
833 | // ResetConnectBackoff wakes up all subchannels in transient failure and causes | ||
834 | // them to attempt another connection immediately. It also resets the backoff | ||
835 | // times used for subsequent attempts regardless of the current state. | ||
836 | // | ||
837 | // In general, this function should not be used. Typical service or network | ||
838 | // outages result in a reasonable client reconnection strategy by default. | ||
839 | // However, if a previously unavailable network becomes available, this may be | ||
840 | // used to trigger an immediate reconnect. | ||
841 | // | ||
842 | // This API is EXPERIMENTAL. | ||
843 | func (cc *ClientConn) ResetConnectBackoff() { | ||
844 | cc.mu.Lock() | ||
845 | defer cc.mu.Unlock() | ||
846 | for ac := range cc.conns { | ||
847 | ac.resetConnectBackoff() | ||
812 | } | 848 | } |
813 | return t, put, nil | ||
814 | } | 849 | } |
815 | 850 | ||
816 | // Close tears down the ClientConn and all underlying connections. | 851 | // Close tears down the ClientConn and all underlying connections. |
817 | func (cc *ClientConn) Close() error { | 852 | func (cc *ClientConn) Close() error { |
818 | cc.cancel() | 853 | defer cc.cancel() |
819 | 854 | ||
820 | cc.mu.Lock() | 855 | cc.mu.Lock() |
821 | if cc.conns == nil { | 856 | if cc.conns == nil { |
@@ -825,13 +860,41 @@ func (cc *ClientConn) Close() error { | |||
825 | conns := cc.conns | 860 | conns := cc.conns |
826 | cc.conns = nil | 861 | cc.conns = nil |
827 | cc.csMgr.updateState(connectivity.Shutdown) | 862 | cc.csMgr.updateState(connectivity.Shutdown) |
863 | |||
864 | rWrapper := cc.resolverWrapper | ||
865 | cc.resolverWrapper = nil | ||
866 | bWrapper := cc.balancerWrapper | ||
867 | cc.balancerWrapper = nil | ||
828 | cc.mu.Unlock() | 868 | cc.mu.Unlock() |
829 | if cc.dopts.balancer != nil { | 869 | |
830 | cc.dopts.balancer.Close() | 870 | cc.blockingpicker.close() |
871 | |||
872 | if rWrapper != nil { | ||
873 | rWrapper.close() | ||
831 | } | 874 | } |
832 | for _, ac := range conns { | 875 | if bWrapper != nil { |
876 | bWrapper.close() | ||
877 | } | ||
878 | |||
879 | for ac := range conns { | ||
833 | ac.tearDown(ErrClientConnClosing) | 880 | ac.tearDown(ErrClientConnClosing) |
834 | } | 881 | } |
882 | if channelz.IsOn() { | ||
883 | ted := &channelz.TraceEventDesc{ | ||
884 | Desc: "Channel Deleted", | ||
885 | Severity: channelz.CtINFO, | ||
886 | } | ||
887 | if cc.dopts.channelzParentID != 0 { | ||
888 | ted.Parent = &channelz.TraceEventDesc{ | ||
889 | Desc: fmt.Sprintf("Nested channel(id:%d) deleted", cc.channelzID), | ||
890 | Severity: channelz.CtINFO, | ||
891 | } | ||
892 | } | ||
893 | channelz.AddTraceEvent(cc.channelzID, ted) | ||
894 | // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to | ||
895 | // the entity beng deleted, and thus prevent it from being deleted right away. | ||
896 | channelz.RemoveEntry(cc.channelzID) | ||
897 | } | ||
835 | return nil | 898 | return nil |
836 | } | 899 | } |
837 | 900 | ||
@@ -841,29 +904,56 @@ type addrConn struct { | |||
841 | cancel context.CancelFunc | 904 | cancel context.CancelFunc |
842 | 905 | ||
843 | cc *ClientConn | 906 | cc *ClientConn |
844 | addr Address | ||
845 | dopts dialOptions | 907 | dopts dialOptions |
846 | events trace.EventLog | 908 | acbw balancer.SubConn |
909 | scopts balancer.NewSubConnOptions | ||
910 | |||
911 | // transport is set when there's a viable transport (note: ac state may not be READY as LB channel | ||
912 | // health checking may require server to report healthy to set ac to READY), and is reset | ||
913 | // to nil when the current transport should no longer be used to create a stream (e.g. after GoAway | ||
914 | // is received, transport is closed, ac has been torn down). | ||
915 | transport transport.ClientTransport // The current transport. | ||
847 | 916 | ||
848 | csEvltr *connectivityStateEvaluator | 917 | mu sync.Mutex |
918 | curAddr resolver.Address // The current address. | ||
919 | addrs []resolver.Address // All addresses that the resolver resolved to. | ||
849 | 920 | ||
850 | mu sync.Mutex | 921 | // Use updateConnectivityState for updating addrConn's connectivity state. |
851 | state connectivity.State | 922 | state connectivity.State |
852 | down func(error) // the handler called when a connection is down. | 923 | |
853 | // ready is closed and becomes nil when a new transport is up or failed | 924 | tearDownErr error // The reason this addrConn is torn down. |
854 | // due to timeout. | 925 | |
855 | ready chan struct{} | 926 | backoffIdx int // Needs to be stateful for resetConnectBackoff. |
856 | transport transport.ClientTransport | 927 | resetBackoff chan struct{} |
857 | 928 | ||
858 | // The reason this addrConn is torn down. | 929 | channelzID int64 // channelz unique identification number. |
859 | tearDownErr error | 930 | czData *channelzData |
931 | healthCheckEnabled bool | ||
932 | } | ||
933 | |||
934 | // Note: this requires a lock on ac.mu. | ||
935 | func (ac *addrConn) updateConnectivityState(s connectivity.State) { | ||
936 | if ac.state == s { | ||
937 | return | ||
938 | } | ||
939 | |||
940 | updateMsg := fmt.Sprintf("Subchannel Connectivity change to %v", s) | ||
941 | grpclog.Infof(updateMsg) | ||
942 | ac.state = s | ||
943 | if channelz.IsOn() { | ||
944 | channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ | ||
945 | Desc: updateMsg, | ||
946 | Severity: channelz.CtINFO, | ||
947 | }) | ||
948 | } | ||
949 | ac.cc.handleSubConnStateChange(ac.acbw, s) | ||
860 | } | 950 | } |
861 | 951 | ||
862 | // adjustParams updates parameters used to create transports upon | 952 | // adjustParams updates parameters used to create transports upon |
863 | // receiving a GoAway. | 953 | // receiving a GoAway. |
864 | func (ac *addrConn) adjustParams(r transport.GoAwayReason) { | 954 | func (ac *addrConn) adjustParams(r transport.GoAwayReason) { |
865 | switch r { | 955 | switch r { |
866 | case transport.TooManyPings: | 956 | case transport.GoAwayTooManyPings: |
867 | v := 2 * ac.dopts.copts.KeepaliveParams.Time | 957 | v := 2 * ac.dopts.copts.KeepaliveParams.Time |
868 | ac.cc.mu.Lock() | 958 | ac.cc.mu.Lock() |
869 | if v > ac.cc.mkp.Time { | 959 | if v > ac.cc.mkp.Time { |
@@ -873,246 +963,359 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) { | |||
873 | } | 963 | } |
874 | } | 964 | } |
875 | 965 | ||
876 | // printf records an event in ac's event log, unless ac has been closed. | 966 | func (ac *addrConn) resetTransport() { |
877 | // REQUIRES ac.mu is held. | 967 | for i := 0; ; i++ { |
878 | func (ac *addrConn) printf(format string, a ...interface{}) { | 968 | tryNextAddrFromStart := grpcsync.NewEvent() |
879 | if ac.events != nil { | ||
880 | ac.events.Printf(format, a...) | ||
881 | } | ||
882 | } | ||
883 | 969 | ||
884 | // errorf records an error in ac's event log, unless ac has been closed. | ||
885 | // REQUIRES ac.mu is held. | ||
886 | func (ac *addrConn) errorf(format string, a ...interface{}) { | ||
887 | if ac.events != nil { | ||
888 | ac.events.Errorf(format, a...) | ||
889 | } | ||
890 | } | ||
891 | |||
892 | // resetTransport recreates a transport to the address for ac. | ||
893 | // For the old transport: | ||
894 | // - if drain is true, it will be gracefully closed. | ||
895 | // - otherwise, it will be closed. | ||
896 | func (ac *addrConn) resetTransport(drain bool) error { | ||
897 | ac.mu.Lock() | ||
898 | if ac.state == connectivity.Shutdown { | ||
899 | ac.mu.Unlock() | ||
900 | return errConnClosing | ||
901 | } | ||
902 | ac.printf("connecting") | ||
903 | if ac.down != nil { | ||
904 | ac.down(downErrorf(false, true, "%v", errNetworkIO)) | ||
905 | ac.down = nil | ||
906 | } | ||
907 | oldState := ac.state | ||
908 | ac.state = connectivity.Connecting | ||
909 | ac.csEvltr.recordTransition(oldState, ac.state) | ||
910 | t := ac.transport | ||
911 | ac.transport = nil | ||
912 | ac.mu.Unlock() | ||
913 | if t != nil && !drain { | ||
914 | t.Close() | ||
915 | } | ||
916 | ac.cc.mu.RLock() | ||
917 | ac.dopts.copts.KeepaliveParams = ac.cc.mkp | ||
918 | ac.cc.mu.RUnlock() | ||
919 | for retries := 0; ; retries++ { | ||
920 | ac.mu.Lock() | 970 | ac.mu.Lock() |
921 | if ac.state == connectivity.Shutdown { | 971 | if i > 0 { |
922 | // ac.tearDown(...) has been invoked. | 972 | ac.cc.resolveNow(resolver.ResolveNowOption{}) |
923 | ac.mu.Unlock() | ||
924 | return errConnClosing | ||
925 | } | 973 | } |
974 | addrs := ac.addrs | ||
975 | backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx) | ||
926 | ac.mu.Unlock() | 976 | ac.mu.Unlock() |
927 | sleepTime := ac.dopts.bs.backoff(retries) | ||
928 | timeout := minConnectTimeout | ||
929 | if timeout < sleepTime { | ||
930 | timeout = sleepTime | ||
931 | } | ||
932 | ctx, cancel := context.WithTimeout(ac.ctx, timeout) | ||
933 | connectTime := time.Now() | ||
934 | sinfo := transport.TargetInfo{ | ||
935 | Addr: ac.addr.Addr, | ||
936 | Metadata: ac.addr.Metadata, | ||
937 | } | ||
938 | newTransport, err := transport.NewClientTransport(ctx, sinfo, ac.dopts.copts) | ||
939 | // Don't call cancel in success path due to a race in Go 1.6: | ||
940 | // https://github.com/golang/go/issues/15078. | ||
941 | if err != nil { | ||
942 | cancel() | ||
943 | 977 | ||
944 | if e, ok := err.(transport.ConnectionError); ok && !e.Temporary() { | 978 | addrLoop: |
945 | return err | 979 | for _, addr := range addrs { |
980 | ac.mu.Lock() | ||
981 | |||
982 | if ac.state == connectivity.Shutdown { | ||
983 | ac.mu.Unlock() | ||
984 | return | ||
985 | } | ||
986 | ac.updateConnectivityState(connectivity.Connecting) | ||
987 | ac.transport = nil | ||
988 | ac.mu.Unlock() | ||
989 | |||
990 | // This will be the duration that dial gets to finish. | ||
991 | dialDuration := getMinConnectTimeout() | ||
992 | if dialDuration < backoffFor { | ||
993 | // Give dial more time as we keep failing to connect. | ||
994 | dialDuration = backoffFor | ||
946 | } | 995 | } |
947 | grpclog.Warningf("grpc: addrConn.resetTransport failed to create client transport: %v; Reconnecting to %v", err, ac.addr) | 996 | connectDeadline := time.Now().Add(dialDuration) |
997 | |||
948 | ac.mu.Lock() | 998 | ac.mu.Lock() |
999 | ac.cc.mu.RLock() | ||
1000 | ac.dopts.copts.KeepaliveParams = ac.cc.mkp | ||
1001 | ac.cc.mu.RUnlock() | ||
1002 | |||
949 | if ac.state == connectivity.Shutdown { | 1003 | if ac.state == connectivity.Shutdown { |
950 | // ac.tearDown(...) has been invoked. | ||
951 | ac.mu.Unlock() | 1004 | ac.mu.Unlock() |
952 | return errConnClosing | 1005 | return |
953 | } | 1006 | } |
954 | ac.errorf("transient failure: %v", err) | 1007 | |
955 | oldState = ac.state | 1008 | copts := ac.dopts.copts |
956 | ac.state = connectivity.TransientFailure | 1009 | if ac.scopts.CredsBundle != nil { |
957 | ac.csEvltr.recordTransition(oldState, ac.state) | 1010 | copts.CredsBundle = ac.scopts.CredsBundle |
958 | if ac.ready != nil { | ||
959 | close(ac.ready) | ||
960 | ac.ready = nil | ||
961 | } | 1011 | } |
1012 | hctx, hcancel := context.WithCancel(ac.ctx) | ||
1013 | defer hcancel() | ||
962 | ac.mu.Unlock() | 1014 | ac.mu.Unlock() |
963 | timer := time.NewTimer(sleepTime - time.Since(connectTime)) | 1015 | |
964 | select { | 1016 | if channelz.IsOn() { |
965 | case <-timer.C: | 1017 | channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ |
966 | case <-ac.ctx.Done(): | 1018 | Desc: fmt.Sprintf("Subchannel picks a new address %q to connect", addr.Addr), |
967 | timer.Stop() | 1019 | Severity: channelz.CtINFO, |
968 | return ac.ctx.Err() | 1020 | }) |
1021 | } | ||
1022 | |||
1023 | reconnect := grpcsync.NewEvent() | ||
1024 | prefaceReceived := make(chan struct{}) | ||
1025 | newTr, err := ac.createTransport(addr, copts, connectDeadline, reconnect, prefaceReceived) | ||
1026 | if err == nil { | ||
1027 | ac.mu.Lock() | ||
1028 | ac.curAddr = addr | ||
1029 | ac.transport = newTr | ||
1030 | ac.mu.Unlock() | ||
1031 | |||
1032 | healthCheckConfig := ac.cc.healthCheckConfig() | ||
1033 | // LB channel health checking is only enabled when all the four requirements below are met: | ||
1034 | // 1. it is not disabled by the user with the WithDisableHealthCheck DialOption, | ||
1035 | // 2. the internal.HealthCheckFunc is set by importing the grpc/healthcheck package, | ||
1036 | // 3. a service config with non-empty healthCheckConfig field is provided, | ||
1037 | // 4. the current load balancer allows it. | ||
1038 | healthcheckManagingState := false | ||
1039 | if !ac.cc.dopts.disableHealthCheck && healthCheckConfig != nil && ac.scopts.HealthCheckEnabled { | ||
1040 | if ac.cc.dopts.healthCheckFunc == nil { | ||
1041 | // TODO: add a link to the health check doc in the error message. | ||
1042 | grpclog.Error("the client side LB channel health check function has not been set.") | ||
1043 | } else { | ||
1044 | // TODO(deklerk) refactor to just return transport | ||
1045 | go ac.startHealthCheck(hctx, newTr, addr, healthCheckConfig.ServiceName) | ||
1046 | healthcheckManagingState = true | ||
1047 | } | ||
1048 | } | ||
1049 | if !healthcheckManagingState { | ||
1050 | ac.mu.Lock() | ||
1051 | ac.updateConnectivityState(connectivity.Ready) | ||
1052 | ac.mu.Unlock() | ||
1053 | } | ||
1054 | } else { | ||
1055 | hcancel() | ||
1056 | if err == errConnClosing { | ||
1057 | return | ||
1058 | } | ||
1059 | |||
1060 | if tryNextAddrFromStart.HasFired() { | ||
1061 | break addrLoop | ||
1062 | } | ||
1063 | continue | ||
1064 | } | ||
1065 | |||
1066 | ac.mu.Lock() | ||
1067 | reqHandshake := ac.dopts.reqHandshake | ||
1068 | ac.mu.Unlock() | ||
1069 | |||
1070 | <-reconnect.Done() | ||
1071 | hcancel() | ||
1072 | |||
1073 | if reqHandshake == envconfig.RequireHandshakeHybrid { | ||
1074 | // In RequireHandshakeHybrid mode, we must check to see whether | ||
1075 | // server preface has arrived yet to decide whether to start | ||
1076 | // reconnecting at the top of the list (server preface received) | ||
1077 | // or continue with the next addr in the list as if the | ||
1078 | // connection were not successful (server preface not received). | ||
1079 | select { | ||
1080 | case <-prefaceReceived: | ||
1081 | // We received a server preface - huzzah! We consider this | ||
1082 | // a success and restart from the top of the addr list. | ||
1083 | ac.mu.Lock() | ||
1084 | ac.backoffIdx = 0 | ||
1085 | ac.mu.Unlock() | ||
1086 | break addrLoop | ||
1087 | default: | ||
1088 | // Despite having set state to READY, in hybrid mode we | ||
1089 | // consider this a failure and continue connecting at the | ||
1090 | // next addr in the list. | ||
1091 | ac.mu.Lock() | ||
1092 | if ac.state == connectivity.Shutdown { | ||
1093 | ac.mu.Unlock() | ||
1094 | return | ||
1095 | } | ||
1096 | |||
1097 | ac.updateConnectivityState(connectivity.TransientFailure) | ||
1098 | ac.mu.Unlock() | ||
1099 | |||
1100 | if tryNextAddrFromStart.HasFired() { | ||
1101 | break addrLoop | ||
1102 | } | ||
1103 | } | ||
1104 | } else { | ||
1105 | // In RequireHandshakeOn mode, we would have already waited for | ||
1106 | // the server preface, so we consider this a success and restart | ||
1107 | // from the top of the addr list. In RequireHandshakeOff mode, | ||
1108 | // we don't care to wait for the server preface before | ||
1109 | // considering this a success, so we also restart from the top | ||
1110 | // of the addr list. | ||
1111 | ac.mu.Lock() | ||
1112 | ac.backoffIdx = 0 | ||
1113 | ac.mu.Unlock() | ||
1114 | break addrLoop | ||
969 | } | 1115 | } |
970 | timer.Stop() | ||
971 | continue | ||
972 | } | 1116 | } |
1117 | |||
1118 | // After exhausting all addresses, or after need to reconnect after a | ||
1119 | // READY, the addrConn enters TRANSIENT_FAILURE. | ||
973 | ac.mu.Lock() | 1120 | ac.mu.Lock() |
974 | ac.printf("ready") | ||
975 | if ac.state == connectivity.Shutdown { | 1121 | if ac.state == connectivity.Shutdown { |
976 | // ac.tearDown(...) has been invoked. | ||
977 | ac.mu.Unlock() | 1122 | ac.mu.Unlock() |
978 | newTransport.Close() | 1123 | return |
979 | return errConnClosing | ||
980 | } | ||
981 | oldState = ac.state | ||
982 | ac.state = connectivity.Ready | ||
983 | ac.csEvltr.recordTransition(oldState, ac.state) | ||
984 | ac.transport = newTransport | ||
985 | if ac.ready != nil { | ||
986 | close(ac.ready) | ||
987 | ac.ready = nil | ||
988 | } | ||
989 | if ac.cc.dopts.balancer != nil { | ||
990 | ac.down = ac.cc.dopts.balancer.Up(ac.addr) | ||
991 | } | 1124 | } |
1125 | ac.updateConnectivityState(connectivity.TransientFailure) | ||
1126 | |||
1127 | // Backoff. | ||
1128 | b := ac.resetBackoff | ||
1129 | timer := time.NewTimer(backoffFor) | ||
1130 | acctx := ac.ctx | ||
992 | ac.mu.Unlock() | 1131 | ac.mu.Unlock() |
993 | return nil | 1132 | |
1133 | select { | ||
1134 | case <-timer.C: | ||
1135 | ac.mu.Lock() | ||
1136 | ac.backoffIdx++ | ||
1137 | ac.mu.Unlock() | ||
1138 | case <-b: | ||
1139 | timer.Stop() | ||
1140 | case <-acctx.Done(): | ||
1141 | timer.Stop() | ||
1142 | return | ||
1143 | } | ||
994 | } | 1144 | } |
995 | } | 1145 | } |
996 | 1146 | ||
997 | // Run in a goroutine to track the error in transport and create the | 1147 | // createTransport creates a connection to one of the backends in addrs. It |
998 | // new transport if an error happens. It returns when the channel is closing. | 1148 | // sets ac.transport in the success case, or it returns an error if it was |
999 | func (ac *addrConn) transportMonitor() { | 1149 | // unable to successfully create a transport. |
1000 | for { | 1150 | // |
1151 | // If waitForHandshake is enabled, it blocks until server preface arrives. | ||
1152 | func (ac *addrConn) createTransport(addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time, reconnect *grpcsync.Event, prefaceReceived chan struct{}) (transport.ClientTransport, error) { | ||
1153 | onCloseCalled := make(chan struct{}) | ||
1154 | |||
1155 | target := transport.TargetInfo{ | ||
1156 | Addr: addr.Addr, | ||
1157 | Metadata: addr.Metadata, | ||
1158 | Authority: ac.cc.authority, | ||
1159 | } | ||
1160 | |||
1161 | prefaceTimer := time.NewTimer(connectDeadline.Sub(time.Now())) | ||
1162 | |||
1163 | onGoAway := func(r transport.GoAwayReason) { | ||
1001 | ac.mu.Lock() | 1164 | ac.mu.Lock() |
1002 | t := ac.transport | 1165 | ac.adjustParams(r) |
1003 | ac.mu.Unlock() | 1166 | ac.mu.Unlock() |
1004 | select { | 1167 | reconnect.Fire() |
1005 | // This is needed to detect the teardown when | 1168 | } |
1006 | // the addrConn is idle (i.e., no RPC in flight). | 1169 | |
1007 | case <-ac.ctx.Done(): | 1170 | onClose := func() { |
1008 | select { | 1171 | close(onCloseCalled) |
1009 | case <-t.Error(): | 1172 | prefaceTimer.Stop() |
1010 | t.Close() | 1173 | reconnect.Fire() |
1011 | default: | 1174 | } |
1012 | } | 1175 | |
1013 | return | 1176 | onPrefaceReceipt := func() { |
1014 | case <-t.GoAway(): | 1177 | close(prefaceReceived) |
1015 | ac.adjustParams(t.GetGoAwayReason()) | 1178 | prefaceTimer.Stop() |
1016 | // If GoAway happens without any network I/O error, the underlying transport | 1179 | } |
1017 | // will be gracefully closed, and a new transport will be created. | 1180 | |
1018 | // (The transport will be closed when all the pending RPCs finished or failed.) | 1181 | connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline) |
1019 | // If GoAway and some network I/O error happen concurrently, the underlying transport | 1182 | defer cancel() |
1020 | // will be closed, and a new transport will be created. | 1183 | if channelz.IsOn() { |
1021 | var drain bool | 1184 | copts.ChannelzParentID = ac.channelzID |
1185 | } | ||
1186 | |||
1187 | newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, target, copts, onPrefaceReceipt, onGoAway, onClose) | ||
1188 | |||
1189 | if err == nil { | ||
1190 | if ac.dopts.reqHandshake == envconfig.RequireHandshakeOn { | ||
1022 | select { | 1191 | select { |
1023 | case <-t.Error(): | 1192 | case <-prefaceTimer.C: |
1024 | default: | 1193 | // We didn't get the preface in time. |
1025 | drain = true | 1194 | newTr.Close() |
1026 | } | 1195 | err = errors.New("timed out waiting for server handshake") |
1027 | if err := ac.resetTransport(drain); err != nil { | 1196 | case <-prefaceReceived: |
1028 | grpclog.Infof("get error from resetTransport %v, transportMonitor returning", err) | 1197 | // We got the preface - huzzah! things are good. |
1029 | if err != errConnClosing { | 1198 | case <-onCloseCalled: |
1030 | // Keep this ac in cc.conns, to get the reason it's torn down. | 1199 | // The transport has already closed - noop. |
1031 | ac.tearDown(err) | 1200 | return nil, errors.New("connection closed") |
1032 | } | ||
1033 | return | ||
1034 | } | 1201 | } |
1035 | case <-t.Error(): | 1202 | } else if ac.dopts.reqHandshake == envconfig.RequireHandshakeHybrid { |
1036 | select { | 1203 | go func() { |
1037 | case <-ac.ctx.Done(): | 1204 | select { |
1038 | t.Close() | 1205 | case <-prefaceTimer.C: |
1039 | return | 1206 | // We didn't get the preface in time. |
1040 | case <-t.GoAway(): | 1207 | newTr.Close() |
1041 | ac.adjustParams(t.GetGoAwayReason()) | 1208 | case <-prefaceReceived: |
1042 | if err := ac.resetTransport(false); err != nil { | 1209 | // We got the preface just in the nick of time - huzzah! |
1043 | grpclog.Infof("get error from resetTransport %v, transportMonitor returning", err) | 1210 | case <-onCloseCalled: |
1044 | if err != errConnClosing { | 1211 | // The transport has already closed - noop. |
1045 | // Keep this ac in cc.conns, to get the reason it's torn down. | ||
1046 | ac.tearDown(err) | ||
1047 | } | ||
1048 | return | ||
1049 | } | 1212 | } |
1050 | default: | 1213 | }() |
1051 | } | ||
1052 | ac.mu.Lock() | ||
1053 | if ac.state == connectivity.Shutdown { | ||
1054 | // ac has been shutdown. | ||
1055 | ac.mu.Unlock() | ||
1056 | return | ||
1057 | } | ||
1058 | oldState := ac.state | ||
1059 | ac.state = connectivity.TransientFailure | ||
1060 | ac.csEvltr.recordTransition(oldState, ac.state) | ||
1061 | ac.mu.Unlock() | ||
1062 | if err := ac.resetTransport(false); err != nil { | ||
1063 | grpclog.Infof("get error from resetTransport %v, transportMonitor returning", err) | ||
1064 | ac.mu.Lock() | ||
1065 | ac.printf("transport exiting: %v", err) | ||
1066 | ac.mu.Unlock() | ||
1067 | grpclog.Warningf("grpc: addrConn.transportMonitor exits due to: %v", err) | ||
1068 | if err != errConnClosing { | ||
1069 | // Keep this ac in cc.conns, to get the reason it's torn down. | ||
1070 | ac.tearDown(err) | ||
1071 | } | ||
1072 | return | ||
1073 | } | ||
1074 | } | 1214 | } |
1075 | } | 1215 | } |
1076 | } | ||
1077 | 1216 | ||
1078 | // wait blocks until i) the new transport is up or ii) ctx is done or iii) ac is closed or | 1217 | if err != nil { |
1079 | // iv) transport is in connectivity.TransientFailure and there is a balancer/failfast is true. | 1218 | // newTr is either nil, or closed. |
1080 | func (ac *addrConn) wait(ctx context.Context, hasBalancer, failfast bool) (transport.ClientTransport, error) { | 1219 | ac.cc.blockingpicker.updateConnectionError(err) |
1081 | for { | ||
1082 | ac.mu.Lock() | 1220 | ac.mu.Lock() |
1083 | switch { | 1221 | if ac.state == connectivity.Shutdown { |
1084 | case ac.state == connectivity.Shutdown: | 1222 | // ac.tearDown(...) has been invoked. |
1085 | if failfast || !hasBalancer { | ||
1086 | // RPC is failfast or balancer is nil. This RPC should fail with ac.tearDownErr. | ||
1087 | err := ac.tearDownErr | ||
1088 | ac.mu.Unlock() | ||
1089 | return nil, err | ||
1090 | } | ||
1091 | ac.mu.Unlock() | 1223 | ac.mu.Unlock() |
1224 | |||
1092 | return nil, errConnClosing | 1225 | return nil, errConnClosing |
1093 | case ac.state == connectivity.Ready: | 1226 | } |
1094 | ct := ac.transport | 1227 | ac.mu.Unlock() |
1095 | ac.mu.Unlock() | 1228 | grpclog.Warningf("grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting...", addr, err) |
1096 | return ct, nil | 1229 | return nil, err |
1097 | case ac.state == connectivity.TransientFailure: | 1230 | } |
1098 | if failfast || hasBalancer { | 1231 | |
1099 | ac.mu.Unlock() | 1232 | // Now there is a viable transport to be use, so set ac.transport to reflect the new viable transport. |
1100 | return nil, errConnUnavailable | 1233 | ac.mu.Lock() |
1234 | if ac.state == connectivity.Shutdown { | ||
1235 | ac.mu.Unlock() | ||
1236 | newTr.Close() | ||
1237 | return nil, errConnClosing | ||
1238 | } | ||
1239 | ac.mu.Unlock() | ||
1240 | |||
1241 | // Now there is a viable transport to be use, so set ac.transport to reflect the new viable transport. | ||
1242 | ac.mu.Lock() | ||
1243 | if ac.state == connectivity.Shutdown { | ||
1244 | ac.mu.Unlock() | ||
1245 | newTr.Close() | ||
1246 | return nil, errConnClosing | ||
1247 | } | ||
1248 | ac.mu.Unlock() | ||
1249 | |||
1250 | return newTr, nil | ||
1251 | } | ||
1252 | |||
1253 | func (ac *addrConn) startHealthCheck(ctx context.Context, newTr transport.ClientTransport, addr resolver.Address, serviceName string) { | ||
1254 | // Set up the health check helper functions | ||
1255 | newStream := func() (interface{}, error) { | ||
1256 | return ac.newClientStream(ctx, &StreamDesc{ServerStreams: true}, "/grpc.health.v1.Health/Watch", newTr) | ||
1257 | } | ||
1258 | firstReady := true | ||
1259 | reportHealth := func(ok bool) { | ||
1260 | ac.mu.Lock() | ||
1261 | defer ac.mu.Unlock() | ||
1262 | if ac.transport != newTr { | ||
1263 | return | ||
1264 | } | ||
1265 | if ok { | ||
1266 | if firstReady { | ||
1267 | firstReady = false | ||
1268 | ac.curAddr = addr | ||
1101 | } | 1269 | } |
1270 | ac.updateConnectivityState(connectivity.Ready) | ||
1271 | } else { | ||
1272 | ac.updateConnectivityState(connectivity.TransientFailure) | ||
1102 | } | 1273 | } |
1103 | ready := ac.ready | 1274 | } |
1104 | if ready == nil { | 1275 | err := ac.cc.dopts.healthCheckFunc(ctx, newStream, reportHealth, serviceName) |
1105 | ready = make(chan struct{}) | 1276 | if err != nil { |
1106 | ac.ready = ready | 1277 | if status.Code(err) == codes.Unimplemented { |
1278 | if channelz.IsOn() { | ||
1279 | channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ | ||
1280 | Desc: "Subchannel health check is unimplemented at server side, thus health check is disabled", | ||
1281 | Severity: channelz.CtError, | ||
1282 | }) | ||
1283 | } | ||
1284 | grpclog.Error("Subchannel health check is unimplemented at server side, thus health check is disabled") | ||
1285 | } else { | ||
1286 | grpclog.Errorf("HealthCheckFunc exits with unexpected error %v", err) | ||
1107 | } | 1287 | } |
1288 | } | ||
1289 | } | ||
1290 | |||
1291 | func (ac *addrConn) resetConnectBackoff() { | ||
1292 | ac.mu.Lock() | ||
1293 | close(ac.resetBackoff) | ||
1294 | ac.backoffIdx = 0 | ||
1295 | ac.resetBackoff = make(chan struct{}) | ||
1296 | ac.mu.Unlock() | ||
1297 | } | ||
1298 | |||
1299 | // getReadyTransport returns the transport if ac's state is READY. | ||
1300 | // Otherwise it returns nil, false. | ||
1301 | // If ac's state is IDLE, it will trigger ac to connect. | ||
1302 | func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) { | ||
1303 | ac.mu.Lock() | ||
1304 | if ac.state == connectivity.Ready && ac.transport != nil { | ||
1305 | t := ac.transport | ||
1108 | ac.mu.Unlock() | 1306 | ac.mu.Unlock() |
1109 | select { | 1307 | return t, true |
1110 | case <-ctx.Done(): | 1308 | } |
1111 | return nil, toRPCErr(ctx.Err()) | 1309 | var idle bool |
1112 | // Wait until the new transport is ready or failed. | 1310 | if ac.state == connectivity.Idle { |
1113 | case <-ready: | 1311 | idle = true |
1114 | } | ||
1115 | } | 1312 | } |
1313 | ac.mu.Unlock() | ||
1314 | // Trigger idle ac to connect. | ||
1315 | if idle { | ||
1316 | ac.connect() | ||
1317 | } | ||
1318 | return nil, false | ||
1116 | } | 1319 | } |
1117 | 1320 | ||
1118 | // tearDown starts to tear down the addrConn. | 1321 | // tearDown starts to tear down the addrConn. |
@@ -1121,38 +1324,126 @@ func (ac *addrConn) wait(ctx context.Context, hasBalancer, failfast bool) (trans | |||
1121 | // tight loop. | 1324 | // tight loop. |
1122 | // tearDown doesn't remove ac from ac.cc.conns. | 1325 | // tearDown doesn't remove ac from ac.cc.conns. |
1123 | func (ac *addrConn) tearDown(err error) { | 1326 | func (ac *addrConn) tearDown(err error) { |
1124 | ac.cancel() | ||
1125 | |||
1126 | ac.mu.Lock() | 1327 | ac.mu.Lock() |
1127 | defer ac.mu.Unlock() | 1328 | if ac.state == connectivity.Shutdown { |
1128 | if ac.down != nil { | 1329 | ac.mu.Unlock() |
1129 | ac.down(downErrorf(false, false, "%v", err)) | 1330 | return |
1130 | ac.down = nil | ||
1131 | } | 1331 | } |
1132 | if err == errConnDrain && ac.transport != nil { | 1332 | curTr := ac.transport |
1333 | ac.transport = nil | ||
1334 | // We have to set the state to Shutdown before anything else to prevent races | ||
1335 | // between setting the state and logic that waits on context cancelation / etc. | ||
1336 | ac.updateConnectivityState(connectivity.Shutdown) | ||
1337 | ac.cancel() | ||
1338 | ac.tearDownErr = err | ||
1339 | ac.curAddr = resolver.Address{} | ||
1340 | if err == errConnDrain && curTr != nil { | ||
1133 | // GracefulClose(...) may be executed multiple times when | 1341 | // GracefulClose(...) may be executed multiple times when |
1134 | // i) receiving multiple GoAway frames from the server; or | 1342 | // i) receiving multiple GoAway frames from the server; or |
1135 | // ii) there are concurrent name resolver/Balancer triggered | 1343 | // ii) there are concurrent name resolver/Balancer triggered |
1136 | // address removal and GoAway. | 1344 | // address removal and GoAway. |
1137 | ac.transport.GracefulClose() | 1345 | // We have to unlock and re-lock here because GracefulClose => Close => onClose, which requires locking ac.mu. |
1346 | ac.mu.Unlock() | ||
1347 | curTr.GracefulClose() | ||
1348 | ac.mu.Lock() | ||
1138 | } | 1349 | } |
1139 | if ac.state == connectivity.Shutdown { | 1350 | if channelz.IsOn() { |
1140 | return | 1351 | channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ |
1352 | Desc: "Subchannel Deleted", | ||
1353 | Severity: channelz.CtINFO, | ||
1354 | Parent: &channelz.TraceEventDesc{ | ||
1355 | Desc: fmt.Sprintf("Subchanel(id:%d) deleted", ac.channelzID), | ||
1356 | Severity: channelz.CtINFO, | ||
1357 | }, | ||
1358 | }) | ||
1359 | // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to | ||
1360 | // the entity beng deleted, and thus prevent it from being deleted right away. | ||
1361 | channelz.RemoveEntry(ac.channelzID) | ||
1141 | } | 1362 | } |
1142 | oldState := ac.state | 1363 | ac.mu.Unlock() |
1143 | ac.state = connectivity.Shutdown | 1364 | } |
1144 | ac.tearDownErr = err | 1365 | |
1145 | ac.csEvltr.recordTransition(oldState, ac.state) | 1366 | func (ac *addrConn) getState() connectivity.State { |
1146 | if ac.events != nil { | 1367 | ac.mu.Lock() |
1147 | ac.events.Finish() | 1368 | defer ac.mu.Unlock() |
1148 | ac.events = nil | 1369 | return ac.state |
1370 | } | ||
1371 | |||
1372 | func (ac *addrConn) ChannelzMetric() *channelz.ChannelInternalMetric { | ||
1373 | ac.mu.Lock() | ||
1374 | addr := ac.curAddr.Addr | ||
1375 | ac.mu.Unlock() | ||
1376 | return &channelz.ChannelInternalMetric{ | ||
1377 | State: ac.getState(), | ||
1378 | Target: addr, | ||
1379 | CallsStarted: atomic.LoadInt64(&ac.czData.callsStarted), | ||
1380 | CallsSucceeded: atomic.LoadInt64(&ac.czData.callsSucceeded), | ||
1381 | CallsFailed: atomic.LoadInt64(&ac.czData.callsFailed), | ||
1382 | LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&ac.czData.lastCallStartedTime)), | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | func (ac *addrConn) incrCallsStarted() { | ||
1387 | atomic.AddInt64(&ac.czData.callsStarted, 1) | ||
1388 | atomic.StoreInt64(&ac.czData.lastCallStartedTime, time.Now().UnixNano()) | ||
1389 | } | ||
1390 | |||
1391 | func (ac *addrConn) incrCallsSucceeded() { | ||
1392 | atomic.AddInt64(&ac.czData.callsSucceeded, 1) | ||
1393 | } | ||
1394 | |||
1395 | func (ac *addrConn) incrCallsFailed() { | ||
1396 | atomic.AddInt64(&ac.czData.callsFailed, 1) | ||
1397 | } | ||
1398 | |||
1399 | type retryThrottler struct { | ||
1400 | max float64 | ||
1401 | thresh float64 | ||
1402 | ratio float64 | ||
1403 | |||
1404 | mu sync.Mutex | ||
1405 | tokens float64 // TODO(dfawley): replace with atomic and remove lock. | ||
1406 | } | ||
1407 | |||
1408 | // throttle subtracts a retry token from the pool and returns whether a retry | ||
1409 | // should be throttled (disallowed) based upon the retry throttling policy in | ||
1410 | // the service config. | ||
1411 | func (rt *retryThrottler) throttle() bool { | ||
1412 | if rt == nil { | ||
1413 | return false | ||
1414 | } | ||
1415 | rt.mu.Lock() | ||
1416 | defer rt.mu.Unlock() | ||
1417 | rt.tokens-- | ||
1418 | if rt.tokens < 0 { | ||
1419 | rt.tokens = 0 | ||
1149 | } | 1420 | } |
1150 | if ac.ready != nil { | 1421 | return rt.tokens <= rt.thresh |
1151 | close(ac.ready) | 1422 | } |
1152 | ac.ready = nil | 1423 | |
1424 | func (rt *retryThrottler) successfulRPC() { | ||
1425 | if rt == nil { | ||
1426 | return | ||
1153 | } | 1427 | } |
1154 | if ac.transport != nil && err != errConnDrain { | 1428 | rt.mu.Lock() |
1155 | ac.transport.Close() | 1429 | defer rt.mu.Unlock() |
1430 | rt.tokens += rt.ratio | ||
1431 | if rt.tokens > rt.max { | ||
1432 | rt.tokens = rt.max | ||
1156 | } | 1433 | } |
1157 | return | ||
1158 | } | 1434 | } |
1435 | |||
1436 | type channelzChannel struct { | ||
1437 | cc *ClientConn | ||
1438 | } | ||
1439 | |||
1440 | func (c *channelzChannel) ChannelzMetric() *channelz.ChannelInternalMetric { | ||
1441 | return c.cc.channelzMetric() | ||
1442 | } | ||
1443 | |||
1444 | // ErrClientConnTimeout indicates that the ClientConn cannot establish the | ||
1445 | // underlying connections within the specified timeout. | ||
1446 | // | ||
1447 | // Deprecated: This error is never returned by grpc and should not be | ||
1448 | // referenced by users. | ||
1449 | var ErrClientConnTimeout = errors.New("grpc: timed out when dialing") | ||
diff --git a/vendor/google.golang.org/grpc/codec.go b/vendor/google.golang.org/grpc/codec.go index 905b048..1297765 100644 --- a/vendor/google.golang.org/grpc/codec.go +++ b/vendor/google.golang.org/grpc/codec.go | |||
@@ -19,86 +19,32 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "math" | 22 | "google.golang.org/grpc/encoding" |
23 | "sync" | 23 | _ "google.golang.org/grpc/encoding/proto" // to register the Codec for "proto" |
24 | |||
25 | "github.com/golang/protobuf/proto" | ||
26 | ) | 24 | ) |
27 | 25 | ||
26 | // baseCodec contains the functionality of both Codec and encoding.Codec, but | ||
27 | // omits the name/string, which vary between the two and are not needed for | ||
28 | // anything besides the registry in the encoding package. | ||
29 | type baseCodec interface { | ||
30 | Marshal(v interface{}) ([]byte, error) | ||
31 | Unmarshal(data []byte, v interface{}) error | ||
32 | } | ||
33 | |||
34 | var _ baseCodec = Codec(nil) | ||
35 | var _ baseCodec = encoding.Codec(nil) | ||
36 | |||
28 | // Codec defines the interface gRPC uses to encode and decode messages. | 37 | // Codec defines the interface gRPC uses to encode and decode messages. |
29 | // Note that implementations of this interface must be thread safe; | 38 | // Note that implementations of this interface must be thread safe; |
30 | // a Codec's methods can be called from concurrent goroutines. | 39 | // a Codec's methods can be called from concurrent goroutines. |
40 | // | ||
41 | // Deprecated: use encoding.Codec instead. | ||
31 | type Codec interface { | 42 | type Codec interface { |
32 | // Marshal returns the wire format of v. | 43 | // Marshal returns the wire format of v. |
33 | Marshal(v interface{}) ([]byte, error) | 44 | Marshal(v interface{}) ([]byte, error) |
34 | // Unmarshal parses the wire format into v. | 45 | // Unmarshal parses the wire format into v. |
35 | Unmarshal(data []byte, v interface{}) error | 46 | Unmarshal(data []byte, v interface{}) error |
36 | // String returns the name of the Codec implementation. The returned | 47 | // String returns the name of the Codec implementation. This is unused by |
37 | // string will be used as part of content type in transmission. | 48 | // gRPC. |
38 | String() string | 49 | String() string |
39 | } | 50 | } |
40 | |||
41 | // protoCodec is a Codec implementation with protobuf. It is the default codec for gRPC. | ||
42 | type protoCodec struct { | ||
43 | } | ||
44 | |||
45 | type cachedProtoBuffer struct { | ||
46 | lastMarshaledSize uint32 | ||
47 | proto.Buffer | ||
48 | } | ||
49 | |||
50 | func capToMaxInt32(val int) uint32 { | ||
51 | if val > math.MaxInt32 { | ||
52 | return uint32(math.MaxInt32) | ||
53 | } | ||
54 | return uint32(val) | ||
55 | } | ||
56 | |||
57 | func (p protoCodec) marshal(v interface{}, cb *cachedProtoBuffer) ([]byte, error) { | ||
58 | protoMsg := v.(proto.Message) | ||
59 | newSlice := make([]byte, 0, cb.lastMarshaledSize) | ||
60 | |||
61 | cb.SetBuf(newSlice) | ||
62 | cb.Reset() | ||
63 | if err := cb.Marshal(protoMsg); err != nil { | ||
64 | return nil, err | ||
65 | } | ||
66 | out := cb.Bytes() | ||
67 | cb.lastMarshaledSize = capToMaxInt32(len(out)) | ||
68 | return out, nil | ||
69 | } | ||
70 | |||
71 | func (p protoCodec) Marshal(v interface{}) ([]byte, error) { | ||
72 | cb := protoBufferPool.Get().(*cachedProtoBuffer) | ||
73 | out, err := p.marshal(v, cb) | ||
74 | |||
75 | // put back buffer and lose the ref to the slice | ||
76 | cb.SetBuf(nil) | ||
77 | protoBufferPool.Put(cb) | ||
78 | return out, err | ||
79 | } | ||
80 | |||
81 | func (p protoCodec) Unmarshal(data []byte, v interface{}) error { | ||
82 | cb := protoBufferPool.Get().(*cachedProtoBuffer) | ||
83 | cb.SetBuf(data) | ||
84 | v.(proto.Message).Reset() | ||
85 | err := cb.Unmarshal(v.(proto.Message)) | ||
86 | cb.SetBuf(nil) | ||
87 | protoBufferPool.Put(cb) | ||
88 | return err | ||
89 | } | ||
90 | |||
91 | func (protoCodec) String() string { | ||
92 | return "proto" | ||
93 | } | ||
94 | |||
95 | var ( | ||
96 | protoBufferPool = &sync.Pool{ | ||
97 | New: func() interface{} { | ||
98 | return &cachedProtoBuffer{ | ||
99 | Buffer: proto.Buffer{}, | ||
100 | lastMarshaledSize: 16, | ||
101 | } | ||
102 | }, | ||
103 | } | ||
104 | ) | ||
diff --git a/vendor/google.golang.org/grpc/codes/code_string.go b/vendor/google.golang.org/grpc/codes/code_string.go index e6762d0..0b206a5 100644 --- a/vendor/google.golang.org/grpc/codes/code_string.go +++ b/vendor/google.golang.org/grpc/codes/code_string.go | |||
@@ -1,16 +1,62 @@ | |||
1 | // generated by stringer -type=Code; DO NOT EDIT | 1 | /* |
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
2 | 18 | ||
3 | package codes | 19 | package codes |
4 | 20 | ||
5 | import "fmt" | 21 | import "strconv" |
6 | 22 | ||
7 | const _Code_name = "OKCanceledUnknownInvalidArgumentDeadlineExceededNotFoundAlreadyExistsPermissionDeniedResourceExhaustedFailedPreconditionAbortedOutOfRangeUnimplementedInternalUnavailableDataLossUnauthenticated" | 23 | func (c Code) String() string { |
8 | 24 | switch c { | |
9 | var _Code_index = [...]uint8{0, 2, 10, 17, 32, 48, 56, 69, 85, 102, 120, 127, 137, 150, 158, 169, 177, 192} | 25 | case OK: |
10 | 26 | return "OK" | |
11 | func (i Code) String() string { | 27 | case Canceled: |
12 | if i+1 >= Code(len(_Code_index)) { | 28 | return "Canceled" |
13 | return fmt.Sprintf("Code(%d)", i) | 29 | case Unknown: |
30 | return "Unknown" | ||
31 | case InvalidArgument: | ||
32 | return "InvalidArgument" | ||
33 | case DeadlineExceeded: | ||
34 | return "DeadlineExceeded" | ||
35 | case NotFound: | ||
36 | return "NotFound" | ||
37 | case AlreadyExists: | ||
38 | return "AlreadyExists" | ||
39 | case PermissionDenied: | ||
40 | return "PermissionDenied" | ||
41 | case ResourceExhausted: | ||
42 | return "ResourceExhausted" | ||
43 | case FailedPrecondition: | ||
44 | return "FailedPrecondition" | ||
45 | case Aborted: | ||
46 | return "Aborted" | ||
47 | case OutOfRange: | ||
48 | return "OutOfRange" | ||
49 | case Unimplemented: | ||
50 | return "Unimplemented" | ||
51 | case Internal: | ||
52 | return "Internal" | ||
53 | case Unavailable: | ||
54 | return "Unavailable" | ||
55 | case DataLoss: | ||
56 | return "DataLoss" | ||
57 | case Unauthenticated: | ||
58 | return "Unauthenticated" | ||
59 | default: | ||
60 | return "Code(" + strconv.FormatInt(int64(c), 10) + ")" | ||
14 | } | 61 | } |
15 | return _Code_name[_Code_index[i]:_Code_index[i+1]] | ||
16 | } | 62 | } |
diff --git a/vendor/google.golang.org/grpc/codes/codes.go b/vendor/google.golang.org/grpc/codes/codes.go index 21e7733..d9b9d57 100644 --- a/vendor/google.golang.org/grpc/codes/codes.go +++ b/vendor/google.golang.org/grpc/codes/codes.go | |||
@@ -20,11 +20,14 @@ | |||
20 | // consistent across various languages. | 20 | // consistent across various languages. |
21 | package codes // import "google.golang.org/grpc/codes" | 21 | package codes // import "google.golang.org/grpc/codes" |
22 | 22 | ||
23 | import ( | ||
24 | "fmt" | ||
25 | "strconv" | ||
26 | ) | ||
27 | |||
23 | // A Code is an unsigned 32-bit error code as defined in the gRPC spec. | 28 | // A Code is an unsigned 32-bit error code as defined in the gRPC spec. |
24 | type Code uint32 | 29 | type Code uint32 |
25 | 30 | ||
26 | //go:generate stringer -type=Code | ||
27 | |||
28 | const ( | 31 | const ( |
29 | // OK is returned on success. | 32 | // OK is returned on success. |
30 | OK Code = 0 | 33 | OK Code = 0 |
@@ -32,9 +35,9 @@ const ( | |||
32 | // Canceled indicates the operation was canceled (typically by the caller). | 35 | // Canceled indicates the operation was canceled (typically by the caller). |
33 | Canceled Code = 1 | 36 | Canceled Code = 1 |
34 | 37 | ||
35 | // Unknown error. An example of where this error may be returned is | 38 | // Unknown error. An example of where this error may be returned is |
36 | // if a Status value received from another address space belongs to | 39 | // if a Status value received from another address space belongs to |
37 | // an error-space that is not known in this address space. Also | 40 | // an error-space that is not known in this address space. Also |
38 | // errors raised by APIs that do not return enough error information | 41 | // errors raised by APIs that do not return enough error information |
39 | // may be converted to this error. | 42 | // may be converted to this error. |
40 | Unknown Code = 2 | 43 | Unknown Code = 2 |
@@ -63,15 +66,11 @@ const ( | |||
63 | // PermissionDenied indicates the caller does not have permission to | 66 | // PermissionDenied indicates the caller does not have permission to |
64 | // execute the specified operation. It must not be used for rejections | 67 | // execute the specified operation. It must not be used for rejections |
65 | // caused by exhausting some resource (use ResourceExhausted | 68 | // caused by exhausting some resource (use ResourceExhausted |
66 | // instead for those errors). It must not be | 69 | // instead for those errors). It must not be |
67 | // used if the caller cannot be identified (use Unauthenticated | 70 | // used if the caller cannot be identified (use Unauthenticated |
68 | // instead for those errors). | 71 | // instead for those errors). |
69 | PermissionDenied Code = 7 | 72 | PermissionDenied Code = 7 |
70 | 73 | ||
71 | // Unauthenticated indicates the request does not have valid | ||
72 | // authentication credentials for the operation. | ||
73 | Unauthenticated Code = 16 | ||
74 | |||
75 | // ResourceExhausted indicates some resource has been exhausted, perhaps | 74 | // ResourceExhausted indicates some resource has been exhausted, perhaps |
76 | // a per-user quota, or perhaps the entire file system is out of space. | 75 | // a per-user quota, or perhaps the entire file system is out of space. |
77 | ResourceExhausted Code = 8 | 76 | ResourceExhausted Code = 8 |
@@ -87,7 +86,7 @@ const ( | |||
87 | // (b) Use Aborted if the client should retry at a higher-level | 86 | // (b) Use Aborted if the client should retry at a higher-level |
88 | // (e.g., restarting a read-modify-write sequence). | 87 | // (e.g., restarting a read-modify-write sequence). |
89 | // (c) Use FailedPrecondition if the client should not retry until | 88 | // (c) Use FailedPrecondition if the client should not retry until |
90 | // the system state has been explicitly fixed. E.g., if an "rmdir" | 89 | // the system state has been explicitly fixed. E.g., if an "rmdir" |
91 | // fails because the directory is non-empty, FailedPrecondition | 90 | // fails because the directory is non-empty, FailedPrecondition |
92 | // should be returned since the client should not retry unless | 91 | // should be returned since the client should not retry unless |
93 | // they have first fixed up the directory by deleting files from it. | 92 | // they have first fixed up the directory by deleting files from it. |
@@ -116,7 +115,7 @@ const ( | |||
116 | // file size. | 115 | // file size. |
117 | // | 116 | // |
118 | // There is a fair bit of overlap between FailedPrecondition and | 117 | // There is a fair bit of overlap between FailedPrecondition and |
119 | // OutOfRange. We recommend using OutOfRange (the more specific | 118 | // OutOfRange. We recommend using OutOfRange (the more specific |
120 | // error) when it applies so that callers who are iterating through | 119 | // error) when it applies so that callers who are iterating through |
121 | // a space can easily look for an OutOfRange error to detect when | 120 | // a space can easily look for an OutOfRange error to detect when |
122 | // they are done. | 121 | // they are done. |
@@ -126,8 +125,8 @@ const ( | |||
126 | // supported/enabled in this service. | 125 | // supported/enabled in this service. |
127 | Unimplemented Code = 12 | 126 | Unimplemented Code = 12 |
128 | 127 | ||
129 | // Internal errors. Means some invariants expected by underlying | 128 | // Internal errors. Means some invariants expected by underlying |
130 | // system has been broken. If you see one of these errors, | 129 | // system has been broken. If you see one of these errors, |
131 | // something is very broken. | 130 | // something is very broken. |
132 | Internal Code = 13 | 131 | Internal Code = 13 |
133 | 132 | ||
@@ -141,4 +140,58 @@ const ( | |||
141 | 140 | ||
142 | // DataLoss indicates unrecoverable data loss or corruption. | 141 | // DataLoss indicates unrecoverable data loss or corruption. |
143 | DataLoss Code = 15 | 142 | DataLoss Code = 15 |
143 | |||
144 | // Unauthenticated indicates the request does not have valid | ||
145 | // authentication credentials for the operation. | ||
146 | Unauthenticated Code = 16 | ||
147 | |||
148 | _maxCode = 17 | ||
144 | ) | 149 | ) |
150 | |||
151 | var strToCode = map[string]Code{ | ||
152 | `"OK"`: OK, | ||
153 | `"CANCELLED"`:/* [sic] */ Canceled, | ||
154 | `"UNKNOWN"`: Unknown, | ||
155 | `"INVALID_ARGUMENT"`: InvalidArgument, | ||
156 | `"DEADLINE_EXCEEDED"`: DeadlineExceeded, | ||
157 | `"NOT_FOUND"`: NotFound, | ||
158 | `"ALREADY_EXISTS"`: AlreadyExists, | ||
159 | `"PERMISSION_DENIED"`: PermissionDenied, | ||
160 | `"RESOURCE_EXHAUSTED"`: ResourceExhausted, | ||
161 | `"FAILED_PRECONDITION"`: FailedPrecondition, | ||
162 | `"ABORTED"`: Aborted, | ||
163 | `"OUT_OF_RANGE"`: OutOfRange, | ||
164 | `"UNIMPLEMENTED"`: Unimplemented, | ||
165 | `"INTERNAL"`: Internal, | ||
166 | `"UNAVAILABLE"`: Unavailable, | ||
167 | `"DATA_LOSS"`: DataLoss, | ||
168 | `"UNAUTHENTICATED"`: Unauthenticated, | ||
169 | } | ||
170 | |||
171 | // UnmarshalJSON unmarshals b into the Code. | ||
172 | func (c *Code) UnmarshalJSON(b []byte) error { | ||
173 | // From json.Unmarshaler: By convention, to approximate the behavior of | ||
174 | // Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as | ||
175 | // a no-op. | ||
176 | if string(b) == "null" { | ||
177 | return nil | ||
178 | } | ||
179 | if c == nil { | ||
180 | return fmt.Errorf("nil receiver passed to UnmarshalJSON") | ||
181 | } | ||
182 | |||
183 | if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil { | ||
184 | if ci >= _maxCode { | ||
185 | return fmt.Errorf("invalid code: %q", ci) | ||
186 | } | ||
187 | |||
188 | *c = Code(ci) | ||
189 | return nil | ||
190 | } | ||
191 | |||
192 | if jc, ok := strToCode[string(b)]; ok { | ||
193 | *c = jc | ||
194 | return nil | ||
195 | } | ||
196 | return fmt.Errorf("invalid code: %q", string(b)) | ||
197 | } | ||
diff --git a/vendor/google.golang.org/grpc/connectivity/connectivity.go b/vendor/google.golang.org/grpc/connectivity/connectivity.go index 568ef5d..b1d7dbc 100644 --- a/vendor/google.golang.org/grpc/connectivity/connectivity.go +++ b/vendor/google.golang.org/grpc/connectivity/connectivity.go | |||
@@ -22,7 +22,8 @@ | |||
22 | package connectivity | 22 | package connectivity |
23 | 23 | ||
24 | import ( | 24 | import ( |
25 | "golang.org/x/net/context" | 25 | "context" |
26 | |||
26 | "google.golang.org/grpc/grpclog" | 27 | "google.golang.org/grpc/grpclog" |
27 | ) | 28 | ) |
28 | 29 | ||
diff --git a/vendor/google.golang.org/grpc/coverage.sh b/vendor/google.golang.org/grpc/coverage.sh deleted file mode 100644 index b85f918..0000000 --- a/vendor/google.golang.org/grpc/coverage.sh +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | #!/usr/bin/env bash | ||
2 | |||
3 | |||
4 | set -e | ||
5 | |||
6 | workdir=.cover | ||
7 | profile="$workdir/cover.out" | ||
8 | mode=set | ||
9 | end2endtest="google.golang.org/grpc/test" | ||
10 | |||
11 | generate_cover_data() { | ||
12 | rm -rf "$workdir" | ||
13 | mkdir "$workdir" | ||
14 | |||
15 | for pkg in "$@"; do | ||
16 | if [ $pkg == "google.golang.org/grpc" -o $pkg == "google.golang.org/grpc/transport" -o $pkg == "google.golang.org/grpc/metadata" -o $pkg == "google.golang.org/grpc/credentials" ] | ||
17 | then | ||
18 | f="$workdir/$(echo $pkg | tr / -)" | ||
19 | go test -covermode="$mode" -coverprofile="$f.cover" "$pkg" | ||
20 | go test -covermode="$mode" -coverpkg "$pkg" -coverprofile="$f.e2e.cover" "$end2endtest" | ||
21 | fi | ||
22 | done | ||
23 | |||
24 | echo "mode: $mode" >"$profile" | ||
25 | grep -h -v "^mode:" "$workdir"/*.cover >>"$profile" | ||
26 | } | ||
27 | |||
28 | show_cover_report() { | ||
29 | go tool cover -${1}="$profile" | ||
30 | } | ||
31 | |||
32 | push_to_coveralls() { | ||
33 | goveralls -coverprofile="$profile" | ||
34 | } | ||
35 | |||
36 | generate_cover_data $(go list ./...) | ||
37 | show_cover_report func | ||
38 | case "$1" in | ||
39 | "") | ||
40 | ;; | ||
41 | --html) | ||
42 | show_cover_report html ;; | ||
43 | --coveralls) | ||
44 | push_to_coveralls ;; | ||
45 | *) | ||
46 | echo >&2 "error: invalid option: $1" ;; | ||
47 | esac | ||
48 | rm -rf "$workdir" | ||
diff --git a/vendor/google.golang.org/grpc/credentials/credentials.go b/vendor/google.golang.org/grpc/credentials/credentials.go index 2475fe8..a851560 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials.go +++ b/vendor/google.golang.org/grpc/credentials/credentials.go | |||
@@ -23,6 +23,7 @@ | |||
23 | package credentials // import "google.golang.org/grpc/credentials" | 23 | package credentials // import "google.golang.org/grpc/credentials" |
24 | 24 | ||
25 | import ( | 25 | import ( |
26 | "context" | ||
26 | "crypto/tls" | 27 | "crypto/tls" |
27 | "crypto/x509" | 28 | "crypto/x509" |
28 | "errors" | 29 | "errors" |
@@ -31,13 +32,12 @@ import ( | |||
31 | "net" | 32 | "net" |
32 | "strings" | 33 | "strings" |
33 | 34 | ||
34 | "golang.org/x/net/context" | 35 | "github.com/golang/protobuf/proto" |
36 | "google.golang.org/grpc/credentials/internal" | ||
35 | ) | 37 | ) |
36 | 38 | ||
37 | var ( | 39 | // alpnProtoStr are the specified application level protocols for gRPC. |
38 | // alpnProtoStr are the specified application level protocols for gRPC. | 40 | var alpnProtoStr = []string{"h2"} |
39 | alpnProtoStr = []string{"h2"} | ||
40 | ) | ||
41 | 41 | ||
42 | // PerRPCCredentials defines the common interface for the credentials which need to | 42 | // PerRPCCredentials defines the common interface for the credentials which need to |
43 | // attach security information to every RPC (e.g., oauth2). | 43 | // attach security information to every RPC (e.g., oauth2). |
@@ -45,8 +45,9 @@ type PerRPCCredentials interface { | |||
45 | // GetRequestMetadata gets the current request metadata, refreshing | 45 | // GetRequestMetadata gets the current request metadata, refreshing |
46 | // tokens if required. This should be called by the transport layer on | 46 | // tokens if required. This should be called by the transport layer on |
47 | // each request, and the data should be populated in headers or other | 47 | // each request, and the data should be populated in headers or other |
48 | // context. uri is the URI of the entry point for the request. When | 48 | // context. If a status code is returned, it will be used as the status |
49 | // supported by the underlying implementation, ctx can be used for | 49 | // for the RPC. uri is the URI of the entry point for the request. |
50 | // When supported by the underlying implementation, ctx can be used for | ||
50 | // timeout and cancellation. | 51 | // timeout and cancellation. |
51 | // TODO(zhaoq): Define the set of the qualified keys instead of leaving | 52 | // TODO(zhaoq): Define the set of the qualified keys instead of leaving |
52 | // it as an arbitrary string. | 53 | // it as an arbitrary string. |
@@ -74,11 +75,9 @@ type AuthInfo interface { | |||
74 | AuthType() string | 75 | AuthType() string |
75 | } | 76 | } |
76 | 77 | ||
77 | var ( | 78 | // ErrConnDispatched indicates that rawConn has been dispatched out of gRPC |
78 | // ErrConnDispatched indicates that rawConn has been dispatched out of gRPC | 79 | // and the caller should not close rawConn. |
79 | // and the caller should not close rawConn. | 80 | var ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC") |
80 | ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC") | ||
81 | ) | ||
82 | 81 | ||
83 | // TransportCredentials defines the common interface for all the live gRPC wire | 82 | // TransportCredentials defines the common interface for all the live gRPC wire |
84 | // protocols and supported transport security protocols (e.g., TLS, SSL). | 83 | // protocols and supported transport security protocols (e.g., TLS, SSL). |
@@ -91,10 +90,14 @@ type TransportCredentials interface { | |||
91 | // (io.EOF, context.DeadlineExceeded or err.Temporary() == true). | 90 | // (io.EOF, context.DeadlineExceeded or err.Temporary() == true). |
92 | // If the returned error is a wrapper error, implementations should make sure that | 91 | // If the returned error is a wrapper error, implementations should make sure that |
93 | // the error implements Temporary() to have the correct retry behaviors. | 92 | // the error implements Temporary() to have the correct retry behaviors. |
93 | // | ||
94 | // If the returned net.Conn is closed, it MUST close the net.Conn provided. | ||
94 | ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error) | 95 | ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error) |
95 | // ServerHandshake does the authentication handshake for servers. It returns | 96 | // ServerHandshake does the authentication handshake for servers. It returns |
96 | // the authenticated connection and the corresponding auth information about | 97 | // the authenticated connection and the corresponding auth information about |
97 | // the connection. | 98 | // the connection. |
99 | // | ||
100 | // If the returned net.Conn is closed, it MUST close the net.Conn provided. | ||
98 | ServerHandshake(net.Conn) (net.Conn, AuthInfo, error) | 101 | ServerHandshake(net.Conn) (net.Conn, AuthInfo, error) |
99 | // Info provides the ProtocolInfo of this TransportCredentials. | 102 | // Info provides the ProtocolInfo of this TransportCredentials. |
100 | Info() ProtocolInfo | 103 | Info() ProtocolInfo |
@@ -106,6 +109,25 @@ type TransportCredentials interface { | |||
106 | OverrideServerName(string) error | 109 | OverrideServerName(string) error |
107 | } | 110 | } |
108 | 111 | ||
112 | // Bundle is a combination of TransportCredentials and PerRPCCredentials. | ||
113 | // | ||
114 | // It also contains a mode switching method, so it can be used as a combination | ||
115 | // of different credential policies. | ||
116 | // | ||
117 | // Bundle cannot be used together with individual TransportCredentials. | ||
118 | // PerRPCCredentials from Bundle will be appended to other PerRPCCredentials. | ||
119 | // | ||
120 | // This API is experimental. | ||
121 | type Bundle interface { | ||
122 | TransportCredentials() TransportCredentials | ||
123 | PerRPCCredentials() PerRPCCredentials | ||
124 | // NewWithMode should make a copy of Bundle, and switch mode. Modifying the | ||
125 | // existing Bundle may cause races. | ||
126 | // | ||
127 | // NewWithMode returns nil if the requested mode is not supported. | ||
128 | NewWithMode(mode string) (Bundle, error) | ||
129 | } | ||
130 | |||
109 | // TLSInfo contains the auth information for a TLS authenticated connection. | 131 | // TLSInfo contains the auth information for a TLS authenticated connection. |
110 | // It implements the AuthInfo interface. | 132 | // It implements the AuthInfo interface. |
111 | type TLSInfo struct { | 133 | type TLSInfo struct { |
@@ -117,6 +139,18 @@ func (t TLSInfo) AuthType() string { | |||
117 | return "tls" | 139 | return "tls" |
118 | } | 140 | } |
119 | 141 | ||
142 | // GetSecurityValue returns security info requested by channelz. | ||
143 | func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue { | ||
144 | v := &TLSChannelzSecurityValue{ | ||
145 | StandardName: cipherSuiteLookup[t.State.CipherSuite], | ||
146 | } | ||
147 | // Currently there's no way to get LocalCertificate info from tls package. | ||
148 | if len(t.State.PeerCertificates) > 0 { | ||
149 | v.RemoteCertificate = t.State.PeerCertificates[0].Raw | ||
150 | } | ||
151 | return v | ||
152 | } | ||
153 | |||
120 | // tlsCreds is the credentials required for authenticating a connection using TLS. | 154 | // tlsCreds is the credentials required for authenticating a connection using TLS. |
121 | type tlsCreds struct { | 155 | type tlsCreds struct { |
122 | // TLS configuration | 156 | // TLS configuration |
@@ -131,15 +165,15 @@ func (c tlsCreds) Info() ProtocolInfo { | |||
131 | } | 165 | } |
132 | } | 166 | } |
133 | 167 | ||
134 | func (c *tlsCreds) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) { | 168 | func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) { |
135 | // use local cfg to avoid clobbering ServerName if using multiple endpoints | 169 | // use local cfg to avoid clobbering ServerName if using multiple endpoints |
136 | cfg := cloneTLSConfig(c.config) | 170 | cfg := cloneTLSConfig(c.config) |
137 | if cfg.ServerName == "" { | 171 | if cfg.ServerName == "" { |
138 | colonPos := strings.LastIndex(addr, ":") | 172 | colonPos := strings.LastIndex(authority, ":") |
139 | if colonPos == -1 { | 173 | if colonPos == -1 { |
140 | colonPos = len(addr) | 174 | colonPos = len(authority) |
141 | } | 175 | } |
142 | cfg.ServerName = addr[:colonPos] | 176 | cfg.ServerName = authority[:colonPos] |
143 | } | 177 | } |
144 | conn := tls.Client(rawConn, cfg) | 178 | conn := tls.Client(rawConn, cfg) |
145 | errChannel := make(chan error, 1) | 179 | errChannel := make(chan error, 1) |
@@ -154,7 +188,7 @@ func (c *tlsCreds) ClientHandshake(ctx context.Context, addr string, rawConn net | |||
154 | case <-ctx.Done(): | 188 | case <-ctx.Done(): |
155 | return nil, nil, ctx.Err() | 189 | return nil, nil, ctx.Err() |
156 | } | 190 | } |
157 | return conn, TLSInfo{conn.ConnectionState()}, nil | 191 | return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil |
158 | } | 192 | } |
159 | 193 | ||
160 | func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) { | 194 | func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) { |
@@ -162,7 +196,7 @@ func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) | |||
162 | if err := conn.Handshake(); err != nil { | 196 | if err := conn.Handshake(); err != nil { |
163 | return nil, nil, err | 197 | return nil, nil, err |
164 | } | 198 | } |
165 | return conn, TLSInfo{conn.ConnectionState()}, nil | 199 | return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil |
166 | } | 200 | } |
167 | 201 | ||
168 | func (c *tlsCreds) Clone() TransportCredentials { | 202 | func (c *tlsCreds) Clone() TransportCredentials { |
@@ -217,3 +251,78 @@ func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error | |||
217 | } | 251 | } |
218 | return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil | 252 | return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil |
219 | } | 253 | } |
254 | |||
255 | // ChannelzSecurityInfo defines the interface that security protocols should implement | ||
256 | // in order to provide security info to channelz. | ||
257 | type ChannelzSecurityInfo interface { | ||
258 | GetSecurityValue() ChannelzSecurityValue | ||
259 | } | ||
260 | |||
261 | // ChannelzSecurityValue defines the interface that GetSecurityValue() return value | ||
262 | // should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue | ||
263 | // and *OtherChannelzSecurityValue. | ||
264 | type ChannelzSecurityValue interface { | ||
265 | isChannelzSecurityValue() | ||
266 | } | ||
267 | |||
268 | // TLSChannelzSecurityValue defines the struct that TLS protocol should return | ||
269 | // from GetSecurityValue(), containing security info like cipher and certificate used. | ||
270 | type TLSChannelzSecurityValue struct { | ||
271 | StandardName string | ||
272 | LocalCertificate []byte | ||
273 | RemoteCertificate []byte | ||
274 | } | ||
275 | |||
276 | func (*TLSChannelzSecurityValue) isChannelzSecurityValue() {} | ||
277 | |||
278 | // OtherChannelzSecurityValue defines the struct that non-TLS protocol should return | ||
279 | // from GetSecurityValue(), which contains protocol specific security info. Note | ||
280 | // the Value field will be sent to users of channelz requesting channel info, and | ||
281 | // thus sensitive info should better be avoided. | ||
282 | type OtherChannelzSecurityValue struct { | ||
283 | Name string | ||
284 | Value proto.Message | ||
285 | } | ||
286 | |||
287 | func (*OtherChannelzSecurityValue) isChannelzSecurityValue() {} | ||
288 | |||
289 | var cipherSuiteLookup = map[uint16]string{ | ||
290 | tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", | ||
291 | tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", | ||
292 | tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", | ||
293 | tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", | ||
294 | tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256", | ||
295 | tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384", | ||
296 | tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", | ||
297 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", | ||
298 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", | ||
299 | tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", | ||
300 | tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", | ||
301 | tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", | ||
302 | tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", | ||
303 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", | ||
304 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", | ||
305 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", | ||
306 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", | ||
307 | tls.TLS_FALLBACK_SCSV: "TLS_FALLBACK_SCSV", | ||
308 | tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256", | ||
309 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", | ||
310 | tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", | ||
311 | tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", | ||
312 | tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", | ||
313 | } | ||
314 | |||
315 | // cloneTLSConfig returns a shallow clone of the exported | ||
316 | // fields of cfg, ignoring the unexported sync.Once, which | ||
317 | // contains a mutex and must not be copied. | ||
318 | // | ||
319 | // If cfg is nil, a new zero tls.Config is returned. | ||
320 | // | ||
321 | // TODO: inline this function if possible. | ||
322 | func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||
323 | if cfg == nil { | ||
324 | return &tls.Config{} | ||
325 | } | ||
326 | |||
327 | return cfg.Clone() | ||
328 | } | ||
diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go b/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go deleted file mode 100644 index 60409aa..0000000 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | // +build go1.7 | ||
2 | // +build !go1.8 | ||
3 | |||
4 | /* | ||
5 | * | ||
6 | * Copyright 2016 gRPC authors. | ||
7 | * | ||
8 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | * you may not use this file except in compliance with the License. | ||
10 | * You may obtain a copy of the License at | ||
11 | * | ||
12 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | * | ||
14 | * Unless required by applicable law or agreed to in writing, software | ||
15 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | * See the License for the specific language governing permissions and | ||
18 | * limitations under the License. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | package credentials | ||
23 | |||
24 | import ( | ||
25 | "crypto/tls" | ||
26 | ) | ||
27 | |||
28 | // cloneTLSConfig returns a shallow clone of the exported | ||
29 | // fields of cfg, ignoring the unexported sync.Once, which | ||
30 | // contains a mutex and must not be copied. | ||
31 | // | ||
32 | // If cfg is nil, a new zero tls.Config is returned. | ||
33 | func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||
34 | if cfg == nil { | ||
35 | return &tls.Config{} | ||
36 | } | ||
37 | return &tls.Config{ | ||
38 | Rand: cfg.Rand, | ||
39 | Time: cfg.Time, | ||
40 | Certificates: cfg.Certificates, | ||
41 | NameToCertificate: cfg.NameToCertificate, | ||
42 | GetCertificate: cfg.GetCertificate, | ||
43 | RootCAs: cfg.RootCAs, | ||
44 | NextProtos: cfg.NextProtos, | ||
45 | ServerName: cfg.ServerName, | ||
46 | ClientAuth: cfg.ClientAuth, | ||
47 | ClientCAs: cfg.ClientCAs, | ||
48 | InsecureSkipVerify: cfg.InsecureSkipVerify, | ||
49 | CipherSuites: cfg.CipherSuites, | ||
50 | PreferServerCipherSuites: cfg.PreferServerCipherSuites, | ||
51 | SessionTicketsDisabled: cfg.SessionTicketsDisabled, | ||
52 | SessionTicketKey: cfg.SessionTicketKey, | ||
53 | ClientSessionCache: cfg.ClientSessionCache, | ||
54 | MinVersion: cfg.MinVersion, | ||
55 | MaxVersion: cfg.MaxVersion, | ||
56 | CurvePreferences: cfg.CurvePreferences, | ||
57 | DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, | ||
58 | Renegotiation: cfg.Renegotiation, | ||
59 | } | ||
60 | } | ||
diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go b/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go deleted file mode 100644 index d6bbcc9..0000000 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | // +build !go1.7 | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2016 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package credentials | ||
22 | |||
23 | import ( | ||
24 | "crypto/tls" | ||
25 | ) | ||
26 | |||
27 | // cloneTLSConfig returns a shallow clone of the exported | ||
28 | // fields of cfg, ignoring the unexported sync.Once, which | ||
29 | // contains a mutex and must not be copied. | ||
30 | // | ||
31 | // If cfg is nil, a new zero tls.Config is returned. | ||
32 | func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||
33 | if cfg == nil { | ||
34 | return &tls.Config{} | ||
35 | } | ||
36 | return &tls.Config{ | ||
37 | Rand: cfg.Rand, | ||
38 | Time: cfg.Time, | ||
39 | Certificates: cfg.Certificates, | ||
40 | NameToCertificate: cfg.NameToCertificate, | ||
41 | GetCertificate: cfg.GetCertificate, | ||
42 | RootCAs: cfg.RootCAs, | ||
43 | NextProtos: cfg.NextProtos, | ||
44 | ServerName: cfg.ServerName, | ||
45 | ClientAuth: cfg.ClientAuth, | ||
46 | ClientCAs: cfg.ClientCAs, | ||
47 | InsecureSkipVerify: cfg.InsecureSkipVerify, | ||
48 | CipherSuites: cfg.CipherSuites, | ||
49 | PreferServerCipherSuites: cfg.PreferServerCipherSuites, | ||
50 | SessionTicketsDisabled: cfg.SessionTicketsDisabled, | ||
51 | SessionTicketKey: cfg.SessionTicketKey, | ||
52 | ClientSessionCache: cfg.ClientSessionCache, | ||
53 | MinVersion: cfg.MinVersion, | ||
54 | MaxVersion: cfg.MaxVersion, | ||
55 | CurvePreferences: cfg.CurvePreferences, | ||
56 | } | ||
57 | } | ||
diff --git a/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go b/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go new file mode 100644 index 0000000..2f4472b --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go | |||
@@ -0,0 +1,61 @@ | |||
1 | // +build !appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | // Package internal contains credentials-internal code. | ||
22 | package internal | ||
23 | |||
24 | import ( | ||
25 | "net" | ||
26 | "syscall" | ||
27 | ) | ||
28 | |||
29 | type sysConn = syscall.Conn | ||
30 | |||
31 | // syscallConn keeps reference of rawConn to support syscall.Conn for channelz. | ||
32 | // SyscallConn() (the method in interface syscall.Conn) is explicitly | ||
33 | // implemented on this type, | ||
34 | // | ||
35 | // Interface syscall.Conn is implemented by most net.Conn implementations (e.g. | ||
36 | // TCPConn, UnixConn), but is not part of net.Conn interface. So wrapper conns | ||
37 | // that embed net.Conn don't implement syscall.Conn. (Side note: tls.Conn | ||
38 | // doesn't embed net.Conn, so even if syscall.Conn is part of net.Conn, it won't | ||
39 | // help here). | ||
40 | type syscallConn struct { | ||
41 | net.Conn | ||
42 | // sysConn is a type alias of syscall.Conn. It's necessary because the name | ||
43 | // `Conn` collides with `net.Conn`. | ||
44 | sysConn | ||
45 | } | ||
46 | |||
47 | // WrapSyscallConn tries to wrap rawConn and newConn into a net.Conn that | ||
48 | // implements syscall.Conn. rawConn will be used to support syscall, and newConn | ||
49 | // will be used for read/write. | ||
50 | // | ||
51 | // This function returns newConn if rawConn doesn't implement syscall.Conn. | ||
52 | func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { | ||
53 | sysConn, ok := rawConn.(syscall.Conn) | ||
54 | if !ok { | ||
55 | return newConn | ||
56 | } | ||
57 | return &syscallConn{ | ||
58 | Conn: newConn, | ||
59 | sysConn: sysConn, | ||
60 | } | ||
61 | } | ||
diff --git a/vendor/google.golang.org/grpc/naming/go17.go b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_appengine.go index a537b08..d4346e9 100644 --- a/vendor/google.golang.org/grpc/naming/go17.go +++ b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_appengine.go | |||
@@ -1,8 +1,8 @@ | |||
1 | // +build go1.6, !go1.8 | 1 | // +build appengine |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * | 4 | * |
5 | * Copyright 2017 gRPC authors. | 5 | * Copyright 2018 gRPC authors. |
6 | * | 6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. | 8 | * you may not use this file except in compliance with the License. |
@@ -18,17 +18,13 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | package naming | 21 | package internal |
22 | 22 | ||
23 | import ( | 23 | import ( |
24 | "net" | 24 | "net" |
25 | |||
26 | "golang.org/x/net/context" | ||
27 | ) | 25 | ) |
28 | 26 | ||
29 | var ( | 27 | // WrapSyscallConn returns newConn on appengine. |
30 | lookupHost = func(ctx context.Context, host string) ([]string, error) { return net.LookupHost(host) } | 28 | func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { |
31 | lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { | 29 | return newConn |
32 | return net.LookupSRV(service, proto, name) | 30 | } |
33 | } | ||
34 | ) | ||
diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go new file mode 100644 index 0000000..f286462 --- /dev/null +++ b/vendor/google.golang.org/grpc/dialoptions.go | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | "fmt" | ||
24 | "net" | ||
25 | "time" | ||
26 | |||
27 | "google.golang.org/grpc/balancer" | ||
28 | "google.golang.org/grpc/credentials" | ||
29 | "google.golang.org/grpc/internal" | ||
30 | "google.golang.org/grpc/internal/backoff" | ||
31 | "google.golang.org/grpc/internal/envconfig" | ||
32 | "google.golang.org/grpc/internal/transport" | ||
33 | "google.golang.org/grpc/keepalive" | ||
34 | "google.golang.org/grpc/resolver" | ||
35 | "google.golang.org/grpc/stats" | ||
36 | ) | ||
37 | |||
38 | // dialOptions configure a Dial call. dialOptions are set by the DialOption | ||
39 | // values passed to Dial. | ||
40 | type dialOptions struct { | ||
41 | unaryInt UnaryClientInterceptor | ||
42 | streamInt StreamClientInterceptor | ||
43 | cp Compressor | ||
44 | dc Decompressor | ||
45 | bs backoff.Strategy | ||
46 | block bool | ||
47 | insecure bool | ||
48 | timeout time.Duration | ||
49 | scChan <-chan ServiceConfig | ||
50 | authority string | ||
51 | copts transport.ConnectOptions | ||
52 | callOptions []CallOption | ||
53 | // This is used by v1 balancer dial option WithBalancer to support v1 | ||
54 | // balancer, and also by WithBalancerName dial option. | ||
55 | balancerBuilder balancer.Builder | ||
56 | // This is to support grpclb. | ||
57 | resolverBuilder resolver.Builder | ||
58 | reqHandshake envconfig.RequireHandshakeSetting | ||
59 | channelzParentID int64 | ||
60 | disableServiceConfig bool | ||
61 | disableRetry bool | ||
62 | disableHealthCheck bool | ||
63 | healthCheckFunc internal.HealthChecker | ||
64 | } | ||
65 | |||
66 | // DialOption configures how we set up the connection. | ||
67 | type DialOption interface { | ||
68 | apply(*dialOptions) | ||
69 | } | ||
70 | |||
71 | // EmptyDialOption does not alter the dial configuration. It can be embedded in | ||
72 | // another structure to build custom dial options. | ||
73 | // | ||
74 | // This API is EXPERIMENTAL. | ||
75 | type EmptyDialOption struct{} | ||
76 | |||
77 | func (EmptyDialOption) apply(*dialOptions) {} | ||
78 | |||
79 | // funcDialOption wraps a function that modifies dialOptions into an | ||
80 | // implementation of the DialOption interface. | ||
81 | type funcDialOption struct { | ||
82 | f func(*dialOptions) | ||
83 | } | ||
84 | |||
85 | func (fdo *funcDialOption) apply(do *dialOptions) { | ||
86 | fdo.f(do) | ||
87 | } | ||
88 | |||
89 | func newFuncDialOption(f func(*dialOptions)) *funcDialOption { | ||
90 | return &funcDialOption{ | ||
91 | f: f, | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // WithWaitForHandshake blocks until the initial settings frame is received from | ||
96 | // the server before assigning RPCs to the connection. | ||
97 | // | ||
98 | // Deprecated: this is the default behavior, and this option will be removed | ||
99 | // after the 1.18 release. | ||
100 | func WithWaitForHandshake() DialOption { | ||
101 | return newFuncDialOption(func(o *dialOptions) { | ||
102 | o.reqHandshake = envconfig.RequireHandshakeOn | ||
103 | }) | ||
104 | } | ||
105 | |||
106 | // WithWriteBufferSize determines how much data can be batched before doing a | ||
107 | // write on the wire. The corresponding memory allocation for this buffer will | ||
108 | // be twice the size to keep syscalls low. The default value for this buffer is | ||
109 | // 32KB. | ||
110 | // | ||
111 | // Zero will disable the write buffer such that each write will be on underlying | ||
112 | // connection. Note: A Send call may not directly translate to a write. | ||
113 | func WithWriteBufferSize(s int) DialOption { | ||
114 | return newFuncDialOption(func(o *dialOptions) { | ||
115 | o.copts.WriteBufferSize = s | ||
116 | }) | ||
117 | } | ||
118 | |||
119 | // WithReadBufferSize lets you set the size of read buffer, this determines how | ||
120 | // much data can be read at most for each read syscall. | ||
121 | // | ||
122 | // The default value for this buffer is 32KB. Zero will disable read buffer for | ||
123 | // a connection so data framer can access the underlying conn directly. | ||
124 | func WithReadBufferSize(s int) DialOption { | ||
125 | return newFuncDialOption(func(o *dialOptions) { | ||
126 | o.copts.ReadBufferSize = s | ||
127 | }) | ||
128 | } | ||
129 | |||
130 | // WithInitialWindowSize returns a DialOption which sets the value for initial | ||
131 | // window size on a stream. The lower bound for window size is 64K and any value | ||
132 | // smaller than that will be ignored. | ||
133 | func WithInitialWindowSize(s int32) DialOption { | ||
134 | return newFuncDialOption(func(o *dialOptions) { | ||
135 | o.copts.InitialWindowSize = s | ||
136 | }) | ||
137 | } | ||
138 | |||
139 | // WithInitialConnWindowSize returns a DialOption which sets the value for | ||
140 | // initial window size on a connection. The lower bound for window size is 64K | ||
141 | // and any value smaller than that will be ignored. | ||
142 | func WithInitialConnWindowSize(s int32) DialOption { | ||
143 | return newFuncDialOption(func(o *dialOptions) { | ||
144 | o.copts.InitialConnWindowSize = s | ||
145 | }) | ||
146 | } | ||
147 | |||
148 | // WithMaxMsgSize returns a DialOption which sets the maximum message size the | ||
149 | // client can receive. | ||
150 | // | ||
151 | // Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. | ||
152 | func WithMaxMsgSize(s int) DialOption { | ||
153 | return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) | ||
154 | } | ||
155 | |||
156 | // WithDefaultCallOptions returns a DialOption which sets the default | ||
157 | // CallOptions for calls over the connection. | ||
158 | func WithDefaultCallOptions(cos ...CallOption) DialOption { | ||
159 | return newFuncDialOption(func(o *dialOptions) { | ||
160 | o.callOptions = append(o.callOptions, cos...) | ||
161 | }) | ||
162 | } | ||
163 | |||
164 | // WithCodec returns a DialOption which sets a codec for message marshaling and | ||
165 | // unmarshaling. | ||
166 | // | ||
167 | // Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead. | ||
168 | func WithCodec(c Codec) DialOption { | ||
169 | return WithDefaultCallOptions(CallCustomCodec(c)) | ||
170 | } | ||
171 | |||
172 | // WithCompressor returns a DialOption which sets a Compressor to use for | ||
173 | // message compression. It has lower priority than the compressor set by the | ||
174 | // UseCompressor CallOption. | ||
175 | // | ||
176 | // Deprecated: use UseCompressor instead. | ||
177 | func WithCompressor(cp Compressor) DialOption { | ||
178 | return newFuncDialOption(func(o *dialOptions) { | ||
179 | o.cp = cp | ||
180 | }) | ||
181 | } | ||
182 | |||
183 | // WithDecompressor returns a DialOption which sets a Decompressor to use for | ||
184 | // incoming message decompression. If incoming response messages are encoded | ||
185 | // using the decompressor's Type(), it will be used. Otherwise, the message | ||
186 | // encoding will be used to look up the compressor registered via | ||
187 | // encoding.RegisterCompressor, which will then be used to decompress the | ||
188 | // message. If no compressor is registered for the encoding, an Unimplemented | ||
189 | // status error will be returned. | ||
190 | // | ||
191 | // Deprecated: use encoding.RegisterCompressor instead. | ||
192 | func WithDecompressor(dc Decompressor) DialOption { | ||
193 | return newFuncDialOption(func(o *dialOptions) { | ||
194 | o.dc = dc | ||
195 | }) | ||
196 | } | ||
197 | |||
198 | // WithBalancer returns a DialOption which sets a load balancer with the v1 API. | ||
199 | // Name resolver will be ignored if this DialOption is specified. | ||
200 | // | ||
201 | // Deprecated: use the new balancer APIs in balancer package and | ||
202 | // WithBalancerName. | ||
203 | func WithBalancer(b Balancer) DialOption { | ||
204 | return newFuncDialOption(func(o *dialOptions) { | ||
205 | o.balancerBuilder = &balancerWrapperBuilder{ | ||
206 | b: b, | ||
207 | } | ||
208 | }) | ||
209 | } | ||
210 | |||
211 | // WithBalancerName sets the balancer that the ClientConn will be initialized | ||
212 | // with. Balancer registered with balancerName will be used. This function | ||
213 | // panics if no balancer was registered by balancerName. | ||
214 | // | ||
215 | // The balancer cannot be overridden by balancer option specified by service | ||
216 | // config. | ||
217 | // | ||
218 | // This is an EXPERIMENTAL API. | ||
219 | func WithBalancerName(balancerName string) DialOption { | ||
220 | builder := balancer.Get(balancerName) | ||
221 | if builder == nil { | ||
222 | panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) | ||
223 | } | ||
224 | return newFuncDialOption(func(o *dialOptions) { | ||
225 | o.balancerBuilder = builder | ||
226 | }) | ||
227 | } | ||
228 | |||
229 | // withResolverBuilder is only for grpclb. | ||
230 | func withResolverBuilder(b resolver.Builder) DialOption { | ||
231 | return newFuncDialOption(func(o *dialOptions) { | ||
232 | o.resolverBuilder = b | ||
233 | }) | ||
234 | } | ||
235 | |||
236 | // WithServiceConfig returns a DialOption which has a channel to read the | ||
237 | // service configuration. | ||
238 | // | ||
239 | // Deprecated: service config should be received through name resolver, as | ||
240 | // specified here. | ||
241 | // https://github.com/grpc/grpc/blob/master/doc/service_config.md | ||
242 | func WithServiceConfig(c <-chan ServiceConfig) DialOption { | ||
243 | return newFuncDialOption(func(o *dialOptions) { | ||
244 | o.scChan = c | ||
245 | }) | ||
246 | } | ||
247 | |||
248 | // WithBackoffMaxDelay configures the dialer to use the provided maximum delay | ||
249 | // when backing off after failed connection attempts. | ||
250 | func WithBackoffMaxDelay(md time.Duration) DialOption { | ||
251 | return WithBackoffConfig(BackoffConfig{MaxDelay: md}) | ||
252 | } | ||
253 | |||
254 | // WithBackoffConfig configures the dialer to use the provided backoff | ||
255 | // parameters after connection failures. | ||
256 | // | ||
257 | // Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up | ||
258 | // for use. | ||
259 | func WithBackoffConfig(b BackoffConfig) DialOption { | ||
260 | return withBackoff(backoff.Exponential{ | ||
261 | MaxDelay: b.MaxDelay, | ||
262 | }) | ||
263 | } | ||
264 | |||
265 | // withBackoff sets the backoff strategy used for connectRetryNum after a failed | ||
266 | // connection attempt. | ||
267 | // | ||
268 | // This can be exported if arbitrary backoff strategies are allowed by gRPC. | ||
269 | func withBackoff(bs backoff.Strategy) DialOption { | ||
270 | return newFuncDialOption(func(o *dialOptions) { | ||
271 | o.bs = bs | ||
272 | }) | ||
273 | } | ||
274 | |||
275 | // WithBlock returns a DialOption which makes caller of Dial blocks until the | ||
276 | // underlying connection is up. Without this, Dial returns immediately and | ||
277 | // connecting the server happens in background. | ||
278 | func WithBlock() DialOption { | ||
279 | return newFuncDialOption(func(o *dialOptions) { | ||
280 | o.block = true | ||
281 | }) | ||
282 | } | ||
283 | |||
284 | // WithInsecure returns a DialOption which disables transport security for this | ||
285 | // ClientConn. Note that transport security is required unless WithInsecure is | ||
286 | // set. | ||
287 | func WithInsecure() DialOption { | ||
288 | return newFuncDialOption(func(o *dialOptions) { | ||
289 | o.insecure = true | ||
290 | }) | ||
291 | } | ||
292 | |||
293 | // WithTransportCredentials returns a DialOption which configures a connection | ||
294 | // level security credentials (e.g., TLS/SSL). This should not be used together | ||
295 | // with WithCredentialsBundle. | ||
296 | func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { | ||
297 | return newFuncDialOption(func(o *dialOptions) { | ||
298 | o.copts.TransportCredentials = creds | ||
299 | }) | ||
300 | } | ||
301 | |||
302 | // WithPerRPCCredentials returns a DialOption which sets credentials and places | ||
303 | // auth state on each outbound RPC. | ||
304 | func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { | ||
305 | return newFuncDialOption(func(o *dialOptions) { | ||
306 | o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) | ||
307 | }) | ||
308 | } | ||
309 | |||
310 | // WithCredentialsBundle returns a DialOption to set a credentials bundle for | ||
311 | // the ClientConn.WithCreds. This should not be used together with | ||
312 | // WithTransportCredentials. | ||
313 | // | ||
314 | // This API is experimental. | ||
315 | func WithCredentialsBundle(b credentials.Bundle) DialOption { | ||
316 | return newFuncDialOption(func(o *dialOptions) { | ||
317 | o.copts.CredsBundle = b | ||
318 | }) | ||
319 | } | ||
320 | |||
321 | // WithTimeout returns a DialOption that configures a timeout for dialing a | ||
322 | // ClientConn initially. This is valid if and only if WithBlock() is present. | ||
323 | // | ||
324 | // Deprecated: use DialContext and context.WithTimeout instead. | ||
325 | func WithTimeout(d time.Duration) DialOption { | ||
326 | return newFuncDialOption(func(o *dialOptions) { | ||
327 | o.timeout = d | ||
328 | }) | ||
329 | } | ||
330 | |||
331 | func withContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { | ||
332 | return newFuncDialOption(func(o *dialOptions) { | ||
333 | o.copts.Dialer = f | ||
334 | }) | ||
335 | } | ||
336 | |||
337 | func init() { | ||
338 | internal.WithContextDialer = withContextDialer | ||
339 | internal.WithResolverBuilder = withResolverBuilder | ||
340 | internal.WithHealthCheckFunc = withHealthCheckFunc | ||
341 | } | ||
342 | |||
343 | // WithDialer returns a DialOption that specifies a function to use for dialing | ||
344 | // network addresses. If FailOnNonTempDialError() is set to true, and an error | ||
345 | // is returned by f, gRPC checks the error's Temporary() method to decide if it | ||
346 | // should try to reconnect to the network address. | ||
347 | func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { | ||
348 | return withContextDialer( | ||
349 | func(ctx context.Context, addr string) (net.Conn, error) { | ||
350 | if deadline, ok := ctx.Deadline(); ok { | ||
351 | return f(addr, deadline.Sub(time.Now())) | ||
352 | } | ||
353 | return f(addr, 0) | ||
354 | }) | ||
355 | } | ||
356 | |||
357 | // WithStatsHandler returns a DialOption that specifies the stats handler for | ||
358 | // all the RPCs and underlying network connections in this ClientConn. | ||
359 | func WithStatsHandler(h stats.Handler) DialOption { | ||
360 | return newFuncDialOption(func(o *dialOptions) { | ||
361 | o.copts.StatsHandler = h | ||
362 | }) | ||
363 | } | ||
364 | |||
365 | // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on | ||
366 | // non-temporary dial errors. If f is true, and dialer returns a non-temporary | ||
367 | // error, gRPC will fail the connection to the network address and won't try to | ||
368 | // reconnect. The default value of FailOnNonTempDialError is false. | ||
369 | // | ||
370 | // FailOnNonTempDialError only affects the initial dial, and does not do | ||
371 | // anything useful unless you are also using WithBlock(). | ||
372 | // | ||
373 | // This is an EXPERIMENTAL API. | ||
374 | func FailOnNonTempDialError(f bool) DialOption { | ||
375 | return newFuncDialOption(func(o *dialOptions) { | ||
376 | o.copts.FailOnNonTempDialError = f | ||
377 | }) | ||
378 | } | ||
379 | |||
380 | // WithUserAgent returns a DialOption that specifies a user agent string for all | ||
381 | // the RPCs. | ||
382 | func WithUserAgent(s string) DialOption { | ||
383 | return newFuncDialOption(func(o *dialOptions) { | ||
384 | o.copts.UserAgent = s | ||
385 | }) | ||
386 | } | ||
387 | |||
388 | // WithKeepaliveParams returns a DialOption that specifies keepalive parameters | ||
389 | // for the client transport. | ||
390 | func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { | ||
391 | return newFuncDialOption(func(o *dialOptions) { | ||
392 | o.copts.KeepaliveParams = kp | ||
393 | }) | ||
394 | } | ||
395 | |||
396 | // WithUnaryInterceptor returns a DialOption that specifies the interceptor for | ||
397 | // unary RPCs. | ||
398 | func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { | ||
399 | return newFuncDialOption(func(o *dialOptions) { | ||
400 | o.unaryInt = f | ||
401 | }) | ||
402 | } | ||
403 | |||
404 | // WithStreamInterceptor returns a DialOption that specifies the interceptor for | ||
405 | // streaming RPCs. | ||
406 | func WithStreamInterceptor(f StreamClientInterceptor) DialOption { | ||
407 | return newFuncDialOption(func(o *dialOptions) { | ||
408 | o.streamInt = f | ||
409 | }) | ||
410 | } | ||
411 | |||
412 | // WithAuthority returns a DialOption that specifies the value to be used as the | ||
413 | // :authority pseudo-header. This value only works with WithInsecure and has no | ||
414 | // effect if TransportCredentials are present. | ||
415 | func WithAuthority(a string) DialOption { | ||
416 | return newFuncDialOption(func(o *dialOptions) { | ||
417 | o.authority = a | ||
418 | }) | ||
419 | } | ||
420 | |||
421 | // WithChannelzParentID returns a DialOption that specifies the channelz ID of | ||
422 | // current ClientConn's parent. This function is used in nested channel creation | ||
423 | // (e.g. grpclb dial). | ||
424 | func WithChannelzParentID(id int64) DialOption { | ||
425 | return newFuncDialOption(func(o *dialOptions) { | ||
426 | o.channelzParentID = id | ||
427 | }) | ||
428 | } | ||
429 | |||
430 | // WithDisableServiceConfig returns a DialOption that causes grpc to ignore any | ||
431 | // service config provided by the resolver and provides a hint to the resolver | ||
432 | // to not fetch service configs. | ||
433 | func WithDisableServiceConfig() DialOption { | ||
434 | return newFuncDialOption(func(o *dialOptions) { | ||
435 | o.disableServiceConfig = true | ||
436 | }) | ||
437 | } | ||
438 | |||
439 | // WithDisableRetry returns a DialOption that disables retries, even if the | ||
440 | // service config enables them. This does not impact transparent retries, which | ||
441 | // will happen automatically if no data is written to the wire or if the RPC is | ||
442 | // unprocessed by the remote server. | ||
443 | // | ||
444 | // Retry support is currently disabled by default, but will be enabled by | ||
445 | // default in the future. Until then, it may be enabled by setting the | ||
446 | // environment variable "GRPC_GO_RETRY" to "on". | ||
447 | // | ||
448 | // This API is EXPERIMENTAL. | ||
449 | func WithDisableRetry() DialOption { | ||
450 | return newFuncDialOption(func(o *dialOptions) { | ||
451 | o.disableRetry = true | ||
452 | }) | ||
453 | } | ||
454 | |||
455 | // WithMaxHeaderListSize returns a DialOption that specifies the maximum | ||
456 | // (uncompressed) size of header list that the client is prepared to accept. | ||
457 | func WithMaxHeaderListSize(s uint32) DialOption { | ||
458 | return newFuncDialOption(func(o *dialOptions) { | ||
459 | o.copts.MaxHeaderListSize = &s | ||
460 | }) | ||
461 | } | ||
462 | |||
463 | // WithDisableHealthCheck disables the LB channel health checking for all SubConns of this ClientConn. | ||
464 | // | ||
465 | // This API is EXPERIMENTAL. | ||
466 | func WithDisableHealthCheck() DialOption { | ||
467 | return newFuncDialOption(func(o *dialOptions) { | ||
468 | o.disableHealthCheck = true | ||
469 | }) | ||
470 | } | ||
471 | |||
472 | // withHealthCheckFunc replaces the default health check function with the provided one. It makes | ||
473 | // tests easier to change the health check function. | ||
474 | // | ||
475 | // For testing purpose only. | ||
476 | func withHealthCheckFunc(f internal.HealthChecker) DialOption { | ||
477 | return newFuncDialOption(func(o *dialOptions) { | ||
478 | o.healthCheckFunc = f | ||
479 | }) | ||
480 | } | ||
481 | |||
482 | func defaultDialOptions() dialOptions { | ||
483 | return dialOptions{ | ||
484 | disableRetry: !envconfig.Retry, | ||
485 | reqHandshake: envconfig.RequireHandshake, | ||
486 | healthCheckFunc: internal.HealthCheckFunc, | ||
487 | copts: transport.ConnectOptions{ | ||
488 | WriteBufferSize: defaultWriteBufSize, | ||
489 | ReadBufferSize: defaultReadBufSize, | ||
490 | }, | ||
491 | } | ||
492 | } | ||
diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go new file mode 100644 index 0000000..ade8b7c --- /dev/null +++ b/vendor/google.golang.org/grpc/encoding/encoding.go | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package encoding defines the interface for the compressor and codec, and | ||
20 | // functions to register and retrieve compressors and codecs. | ||
21 | // | ||
22 | // This package is EXPERIMENTAL. | ||
23 | package encoding | ||
24 | |||
25 | import ( | ||
26 | "io" | ||
27 | "strings" | ||
28 | ) | ||
29 | |||
30 | // Identity specifies the optional encoding for uncompressed streams. | ||
31 | // It is intended for grpc internal use only. | ||
32 | const Identity = "identity" | ||
33 | |||
34 | // Compressor is used for compressing and decompressing when sending or | ||
35 | // receiving messages. | ||
36 | type Compressor interface { | ||
37 | // Compress writes the data written to wc to w after compressing it. If an | ||
38 | // error occurs while initializing the compressor, that error is returned | ||
39 | // instead. | ||
40 | Compress(w io.Writer) (io.WriteCloser, error) | ||
41 | // Decompress reads data from r, decompresses it, and provides the | ||
42 | // uncompressed data via the returned io.Reader. If an error occurs while | ||
43 | // initializing the decompressor, that error is returned instead. | ||
44 | Decompress(r io.Reader) (io.Reader, error) | ||
45 | // Name is the name of the compression codec and is used to set the content | ||
46 | // coding header. The result must be static; the result cannot change | ||
47 | // between calls. | ||
48 | Name() string | ||
49 | } | ||
50 | |||
51 | var registeredCompressor = make(map[string]Compressor) | ||
52 | |||
53 | // RegisterCompressor registers the compressor with gRPC by its name. It can | ||
54 | // be activated when sending an RPC via grpc.UseCompressor(). It will be | ||
55 | // automatically accessed when receiving a message based on the content coding | ||
56 | // header. Servers also use it to send a response with the same encoding as | ||
57 | // the request. | ||
58 | // | ||
59 | // NOTE: this function must only be called during initialization time (i.e. in | ||
60 | // an init() function), and is not thread-safe. If multiple Compressors are | ||
61 | // registered with the same name, the one registered last will take effect. | ||
62 | func RegisterCompressor(c Compressor) { | ||
63 | registeredCompressor[c.Name()] = c | ||
64 | } | ||
65 | |||
66 | // GetCompressor returns Compressor for the given compressor name. | ||
67 | func GetCompressor(name string) Compressor { | ||
68 | return registeredCompressor[name] | ||
69 | } | ||
70 | |||
71 | // Codec defines the interface gRPC uses to encode and decode messages. Note | ||
72 | // that implementations of this interface must be thread safe; a Codec's | ||
73 | // methods can be called from concurrent goroutines. | ||
74 | type Codec interface { | ||
75 | // Marshal returns the wire format of v. | ||
76 | Marshal(v interface{}) ([]byte, error) | ||
77 | // Unmarshal parses the wire format into v. | ||
78 | Unmarshal(data []byte, v interface{}) error | ||
79 | // Name returns the name of the Codec implementation. The returned string | ||
80 | // will be used as part of content type in transmission. The result must be | ||
81 | // static; the result cannot change between calls. | ||
82 | Name() string | ||
83 | } | ||
84 | |||
85 | var registeredCodecs = make(map[string]Codec) | ||
86 | |||
87 | // RegisterCodec registers the provided Codec for use with all gRPC clients and | ||
88 | // servers. | ||
89 | // | ||
90 | // The Codec will be stored and looked up by result of its Name() method, which | ||
91 | // should match the content-subtype of the encoding handled by the Codec. This | ||
92 | // is case-insensitive, and is stored and looked up as lowercase. If the | ||
93 | // result of calling Name() is an empty string, RegisterCodec will panic. See | ||
94 | // Content-Type on | ||
95 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for | ||
96 | // more details. | ||
97 | // | ||
98 | // NOTE: this function must only be called during initialization time (i.e. in | ||
99 | // an init() function), and is not thread-safe. If multiple Compressors are | ||
100 | // registered with the same name, the one registered last will take effect. | ||
101 | func RegisterCodec(codec Codec) { | ||
102 | if codec == nil { | ||
103 | panic("cannot register a nil Codec") | ||
104 | } | ||
105 | contentSubtype := strings.ToLower(codec.Name()) | ||
106 | if contentSubtype == "" { | ||
107 | panic("cannot register Codec with empty string result for String()") | ||
108 | } | ||
109 | registeredCodecs[contentSubtype] = codec | ||
110 | } | ||
111 | |||
112 | // GetCodec gets a registered Codec by content-subtype, or nil if no Codec is | ||
113 | // registered for the content-subtype. | ||
114 | // | ||
115 | // The content-subtype is expected to be lowercase. | ||
116 | func GetCodec(contentSubtype string) Codec { | ||
117 | return registeredCodecs[contentSubtype] | ||
118 | } | ||
diff --git a/vendor/google.golang.org/grpc/encoding/proto/proto.go b/vendor/google.golang.org/grpc/encoding/proto/proto.go new file mode 100644 index 0000000..66b97a6 --- /dev/null +++ b/vendor/google.golang.org/grpc/encoding/proto/proto.go | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package proto defines the protobuf codec. Importing this package will | ||
20 | // register the codec. | ||
21 | package proto | ||
22 | |||
23 | import ( | ||
24 | "math" | ||
25 | "sync" | ||
26 | |||
27 | "github.com/golang/protobuf/proto" | ||
28 | "google.golang.org/grpc/encoding" | ||
29 | ) | ||
30 | |||
31 | // Name is the name registered for the proto compressor. | ||
32 | const Name = "proto" | ||
33 | |||
34 | func init() { | ||
35 | encoding.RegisterCodec(codec{}) | ||
36 | } | ||
37 | |||
38 | // codec is a Codec implementation with protobuf. It is the default codec for gRPC. | ||
39 | type codec struct{} | ||
40 | |||
41 | type cachedProtoBuffer struct { | ||
42 | lastMarshaledSize uint32 | ||
43 | proto.Buffer | ||
44 | } | ||
45 | |||
46 | func capToMaxInt32(val int) uint32 { | ||
47 | if val > math.MaxInt32 { | ||
48 | return uint32(math.MaxInt32) | ||
49 | } | ||
50 | return uint32(val) | ||
51 | } | ||
52 | |||
53 | func marshal(v interface{}, cb *cachedProtoBuffer) ([]byte, error) { | ||
54 | protoMsg := v.(proto.Message) | ||
55 | newSlice := make([]byte, 0, cb.lastMarshaledSize) | ||
56 | |||
57 | cb.SetBuf(newSlice) | ||
58 | cb.Reset() | ||
59 | if err := cb.Marshal(protoMsg); err != nil { | ||
60 | return nil, err | ||
61 | } | ||
62 | out := cb.Bytes() | ||
63 | cb.lastMarshaledSize = capToMaxInt32(len(out)) | ||
64 | return out, nil | ||
65 | } | ||
66 | |||
67 | func (codec) Marshal(v interface{}) ([]byte, error) { | ||
68 | if pm, ok := v.(proto.Marshaler); ok { | ||
69 | // object can marshal itself, no need for buffer | ||
70 | return pm.Marshal() | ||
71 | } | ||
72 | |||
73 | cb := protoBufferPool.Get().(*cachedProtoBuffer) | ||
74 | out, err := marshal(v, cb) | ||
75 | |||
76 | // put back buffer and lose the ref to the slice | ||
77 | cb.SetBuf(nil) | ||
78 | protoBufferPool.Put(cb) | ||
79 | return out, err | ||
80 | } | ||
81 | |||
82 | func (codec) Unmarshal(data []byte, v interface{}) error { | ||
83 | protoMsg := v.(proto.Message) | ||
84 | protoMsg.Reset() | ||
85 | |||
86 | if pu, ok := protoMsg.(proto.Unmarshaler); ok { | ||
87 | // object can unmarshal itself, no need for buffer | ||
88 | return pu.Unmarshal(data) | ||
89 | } | ||
90 | |||
91 | cb := protoBufferPool.Get().(*cachedProtoBuffer) | ||
92 | cb.SetBuf(data) | ||
93 | err := cb.Unmarshal(protoMsg) | ||
94 | cb.SetBuf(nil) | ||
95 | protoBufferPool.Put(cb) | ||
96 | return err | ||
97 | } | ||
98 | |||
99 | func (codec) Name() string { | ||
100 | return Name | ||
101 | } | ||
102 | |||
103 | var protoBufferPool = &sync.Pool{ | ||
104 | New: func() interface{} { | ||
105 | return &cachedProtoBuffer{ | ||
106 | Buffer: proto.Buffer{}, | ||
107 | lastMarshaledSize: 16, | ||
108 | } | ||
109 | }, | ||
110 | } | ||
diff --git a/vendor/google.golang.org/grpc/go.mod b/vendor/google.golang.org/grpc/go.mod new file mode 100644 index 0000000..f296dcf --- /dev/null +++ b/vendor/google.golang.org/grpc/go.mod | |||
@@ -0,0 +1,20 @@ | |||
1 | module google.golang.org/grpc | ||
2 | |||
3 | require ( | ||
4 | cloud.google.com/go v0.26.0 // indirect | ||
5 | github.com/client9/misspell v0.3.4 | ||
6 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b | ||
7 | github.com/golang/mock v1.1.1 | ||
8 | github.com/golang/protobuf v1.2.0 | ||
9 | github.com/kisielk/gotool v1.0.0 // indirect | ||
10 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 | ||
11 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d | ||
12 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be | ||
13 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect | ||
14 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 | ||
15 | golang.org/x/text v0.3.0 // indirect | ||
16 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 | ||
17 | google.golang.org/appengine v1.1.0 // indirect | ||
18 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 | ||
19 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858 | ||
20 | ) | ||
diff --git a/vendor/google.golang.org/grpc/go.sum b/vendor/google.golang.org/grpc/go.sum new file mode 100644 index 0000000..bfb6bb7 --- /dev/null +++ b/vendor/google.golang.org/grpc/go.sum | |||
@@ -0,0 +1,32 @@ | |||
1 | cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= | ||
2 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||
3 | github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= | ||
4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||
5 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= | ||
6 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||
7 | github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= | ||
8 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||
9 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | ||
10 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
11 | github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= | ||
12 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||
13 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc= | ||
14 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||
15 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= | ||
16 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
17 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= | ||
18 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||
19 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= | ||
20 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
21 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= | ||
22 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
23 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||
24 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
25 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= | ||
26 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
27 | google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= | ||
28 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||
29 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= | ||
30 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||
31 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858 h1:wN+eVZ7U+gqdqkec6C6VXR1OFf9a5Ul9ETzeYsYv20g= | ||
32 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||
diff --git a/vendor/google.golang.org/grpc/go16.go b/vendor/google.golang.org/grpc/go16.go deleted file mode 100644 index f3dbf21..0000000 --- a/vendor/google.golang.org/grpc/go16.go +++ /dev/null | |||
@@ -1,98 +0,0 @@ | |||
1 | // +build go1.6,!go1.7 | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2016 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package grpc | ||
22 | |||
23 | import ( | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "net" | ||
27 | "net/http" | ||
28 | "os" | ||
29 | |||
30 | "golang.org/x/net/context" | ||
31 | "google.golang.org/grpc/codes" | ||
32 | "google.golang.org/grpc/status" | ||
33 | "google.golang.org/grpc/transport" | ||
34 | ) | ||
35 | |||
36 | // dialContext connects to the address on the named network. | ||
37 | func dialContext(ctx context.Context, network, address string) (net.Conn, error) { | ||
38 | return (&net.Dialer{Cancel: ctx.Done()}).Dial(network, address) | ||
39 | } | ||
40 | |||
41 | func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { | ||
42 | req.Cancel = ctx.Done() | ||
43 | if err := req.Write(conn); err != nil { | ||
44 | return fmt.Errorf("failed to write the HTTP request: %v", err) | ||
45 | } | ||
46 | return nil | ||
47 | } | ||
48 | |||
49 | // toRPCErr converts an error into an error from the status package. | ||
50 | func toRPCErr(err error) error { | ||
51 | if _, ok := status.FromError(err); ok { | ||
52 | return err | ||
53 | } | ||
54 | switch e := err.(type) { | ||
55 | case transport.StreamError: | ||
56 | return status.Error(e.Code, e.Desc) | ||
57 | case transport.ConnectionError: | ||
58 | return status.Error(codes.Unavailable, e.Desc) | ||
59 | default: | ||
60 | switch err { | ||
61 | case context.DeadlineExceeded: | ||
62 | return status.Error(codes.DeadlineExceeded, err.Error()) | ||
63 | case context.Canceled: | ||
64 | return status.Error(codes.Canceled, err.Error()) | ||
65 | case ErrClientConnClosing: | ||
66 | return status.Error(codes.FailedPrecondition, err.Error()) | ||
67 | } | ||
68 | } | ||
69 | return status.Error(codes.Unknown, err.Error()) | ||
70 | } | ||
71 | |||
72 | // convertCode converts a standard Go error into its canonical code. Note that | ||
73 | // this is only used to translate the error returned by the server applications. | ||
74 | func convertCode(err error) codes.Code { | ||
75 | switch err { | ||
76 | case nil: | ||
77 | return codes.OK | ||
78 | case io.EOF: | ||
79 | return codes.OutOfRange | ||
80 | case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF: | ||
81 | return codes.FailedPrecondition | ||
82 | case os.ErrInvalid: | ||
83 | return codes.InvalidArgument | ||
84 | case context.Canceled: | ||
85 | return codes.Canceled | ||
86 | case context.DeadlineExceeded: | ||
87 | return codes.DeadlineExceeded | ||
88 | } | ||
89 | switch { | ||
90 | case os.IsExist(err): | ||
91 | return codes.AlreadyExists | ||
92 | case os.IsNotExist(err): | ||
93 | return codes.NotFound | ||
94 | case os.IsPermission(err): | ||
95 | return codes.PermissionDenied | ||
96 | } | ||
97 | return codes.Unknown | ||
98 | } | ||
diff --git a/vendor/google.golang.org/grpc/go17.go b/vendor/google.golang.org/grpc/go17.go deleted file mode 100644 index a3421d9..0000000 --- a/vendor/google.golang.org/grpc/go17.go +++ /dev/null | |||
@@ -1,98 +0,0 @@ | |||
1 | // +build go1.7 | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2016 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package grpc | ||
22 | |||
23 | import ( | ||
24 | "context" | ||
25 | "io" | ||
26 | "net" | ||
27 | "net/http" | ||
28 | "os" | ||
29 | |||
30 | netctx "golang.org/x/net/context" | ||
31 | "google.golang.org/grpc/codes" | ||
32 | "google.golang.org/grpc/status" | ||
33 | "google.golang.org/grpc/transport" | ||
34 | ) | ||
35 | |||
36 | // dialContext connects to the address on the named network. | ||
37 | func dialContext(ctx context.Context, network, address string) (net.Conn, error) { | ||
38 | return (&net.Dialer{}).DialContext(ctx, network, address) | ||
39 | } | ||
40 | |||
41 | func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { | ||
42 | req = req.WithContext(ctx) | ||
43 | if err := req.Write(conn); err != nil { | ||
44 | return err | ||
45 | } | ||
46 | return nil | ||
47 | } | ||
48 | |||
49 | // toRPCErr converts an error into an error from the status package. | ||
50 | func toRPCErr(err error) error { | ||
51 | if _, ok := status.FromError(err); ok { | ||
52 | return err | ||
53 | } | ||
54 | switch e := err.(type) { | ||
55 | case transport.StreamError: | ||
56 | return status.Error(e.Code, e.Desc) | ||
57 | case transport.ConnectionError: | ||
58 | return status.Error(codes.Unavailable, e.Desc) | ||
59 | default: | ||
60 | switch err { | ||
61 | case context.DeadlineExceeded, netctx.DeadlineExceeded: | ||
62 | return status.Error(codes.DeadlineExceeded, err.Error()) | ||
63 | case context.Canceled, netctx.Canceled: | ||
64 | return status.Error(codes.Canceled, err.Error()) | ||
65 | case ErrClientConnClosing: | ||
66 | return status.Error(codes.FailedPrecondition, err.Error()) | ||
67 | } | ||
68 | } | ||
69 | return status.Error(codes.Unknown, err.Error()) | ||
70 | } | ||
71 | |||
72 | // convertCode converts a standard Go error into its canonical code. Note that | ||
73 | // this is only used to translate the error returned by the server applications. | ||
74 | func convertCode(err error) codes.Code { | ||
75 | switch err { | ||
76 | case nil: | ||
77 | return codes.OK | ||
78 | case io.EOF: | ||
79 | return codes.OutOfRange | ||
80 | case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF: | ||
81 | return codes.FailedPrecondition | ||
82 | case os.ErrInvalid: | ||
83 | return codes.InvalidArgument | ||
84 | case context.Canceled, netctx.Canceled: | ||
85 | return codes.Canceled | ||
86 | case context.DeadlineExceeded, netctx.DeadlineExceeded: | ||
87 | return codes.DeadlineExceeded | ||
88 | } | ||
89 | switch { | ||
90 | case os.IsExist(err): | ||
91 | return codes.AlreadyExists | ||
92 | case os.IsNotExist(err): | ||
93 | return codes.NotFound | ||
94 | case os.IsPermission(err): | ||
95 | return codes.PermissionDenied | ||
96 | } | ||
97 | return codes.Unknown | ||
98 | } | ||
diff --git a/vendor/google.golang.org/grpc/grpclb.go b/vendor/google.golang.org/grpc/grpclb.go deleted file mode 100644 index f7b6b7d..0000000 --- a/vendor/google.golang.org/grpc/grpclb.go +++ /dev/null | |||
@@ -1,737 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2016 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "errors" | ||
23 | "fmt" | ||
24 | "math/rand" | ||
25 | "net" | ||
26 | "sync" | ||
27 | "time" | ||
28 | |||
29 | "golang.org/x/net/context" | ||
30 | "google.golang.org/grpc/codes" | ||
31 | lbpb "google.golang.org/grpc/grpclb/grpc_lb_v1" | ||
32 | "google.golang.org/grpc/grpclog" | ||
33 | "google.golang.org/grpc/metadata" | ||
34 | "google.golang.org/grpc/naming" | ||
35 | ) | ||
36 | |||
37 | // Client API for LoadBalancer service. | ||
38 | // Mostly copied from generated pb.go file. | ||
39 | // To avoid circular dependency. | ||
40 | type loadBalancerClient struct { | ||
41 | cc *ClientConn | ||
42 | } | ||
43 | |||
44 | func (c *loadBalancerClient) BalanceLoad(ctx context.Context, opts ...CallOption) (*balanceLoadClientStream, error) { | ||
45 | desc := &StreamDesc{ | ||
46 | StreamName: "BalanceLoad", | ||
47 | ServerStreams: true, | ||
48 | ClientStreams: true, | ||
49 | } | ||
50 | stream, err := NewClientStream(ctx, desc, c.cc, "/grpc.lb.v1.LoadBalancer/BalanceLoad", opts...) | ||
51 | if err != nil { | ||
52 | return nil, err | ||
53 | } | ||
54 | x := &balanceLoadClientStream{stream} | ||
55 | return x, nil | ||
56 | } | ||
57 | |||
58 | type balanceLoadClientStream struct { | ||
59 | ClientStream | ||
60 | } | ||
61 | |||
62 | func (x *balanceLoadClientStream) Send(m *lbpb.LoadBalanceRequest) error { | ||
63 | return x.ClientStream.SendMsg(m) | ||
64 | } | ||
65 | |||
66 | func (x *balanceLoadClientStream) Recv() (*lbpb.LoadBalanceResponse, error) { | ||
67 | m := new(lbpb.LoadBalanceResponse) | ||
68 | if err := x.ClientStream.RecvMsg(m); err != nil { | ||
69 | return nil, err | ||
70 | } | ||
71 | return m, nil | ||
72 | } | ||
73 | |||
74 | // NewGRPCLBBalancer creates a grpclb load balancer. | ||
75 | func NewGRPCLBBalancer(r naming.Resolver) Balancer { | ||
76 | return &balancer{ | ||
77 | r: r, | ||
78 | } | ||
79 | } | ||
80 | |||
81 | type remoteBalancerInfo struct { | ||
82 | addr string | ||
83 | // the server name used for authentication with the remote LB server. | ||
84 | name string | ||
85 | } | ||
86 | |||
87 | // grpclbAddrInfo consists of the information of a backend server. | ||
88 | type grpclbAddrInfo struct { | ||
89 | addr Address | ||
90 | connected bool | ||
91 | // dropForRateLimiting indicates whether this particular request should be | ||
92 | // dropped by the client for rate limiting. | ||
93 | dropForRateLimiting bool | ||
94 | // dropForLoadBalancing indicates whether this particular request should be | ||
95 | // dropped by the client for load balancing. | ||
96 | dropForLoadBalancing bool | ||
97 | } | ||
98 | |||
99 | type balancer struct { | ||
100 | r naming.Resolver | ||
101 | target string | ||
102 | mu sync.Mutex | ||
103 | seq int // a sequence number to make sure addrCh does not get stale addresses. | ||
104 | w naming.Watcher | ||
105 | addrCh chan []Address | ||
106 | rbs []remoteBalancerInfo | ||
107 | addrs []*grpclbAddrInfo | ||
108 | next int | ||
109 | waitCh chan struct{} | ||
110 | done bool | ||
111 | expTimer *time.Timer | ||
112 | rand *rand.Rand | ||
113 | |||
114 | clientStats lbpb.ClientStats | ||
115 | } | ||
116 | |||
117 | func (b *balancer) watchAddrUpdates(w naming.Watcher, ch chan []remoteBalancerInfo) error { | ||
118 | updates, err := w.Next() | ||
119 | if err != nil { | ||
120 | grpclog.Warningf("grpclb: failed to get next addr update from watcher: %v", err) | ||
121 | return err | ||
122 | } | ||
123 | b.mu.Lock() | ||
124 | defer b.mu.Unlock() | ||
125 | if b.done { | ||
126 | return ErrClientConnClosing | ||
127 | } | ||
128 | for _, update := range updates { | ||
129 | switch update.Op { | ||
130 | case naming.Add: | ||
131 | var exist bool | ||
132 | for _, v := range b.rbs { | ||
133 | // TODO: Is the same addr with different server name a different balancer? | ||
134 | if update.Addr == v.addr { | ||
135 | exist = true | ||
136 | break | ||
137 | } | ||
138 | } | ||
139 | if exist { | ||
140 | continue | ||
141 | } | ||
142 | md, ok := update.Metadata.(*naming.AddrMetadataGRPCLB) | ||
143 | if !ok { | ||
144 | // TODO: Revisit the handling here and may introduce some fallback mechanism. | ||
145 | grpclog.Errorf("The name resolution contains unexpected metadata %v", update.Metadata) | ||
146 | continue | ||
147 | } | ||
148 | switch md.AddrType { | ||
149 | case naming.Backend: | ||
150 | // TODO: Revisit the handling here and may introduce some fallback mechanism. | ||
151 | grpclog.Errorf("The name resolution does not give grpclb addresses") | ||
152 | continue | ||
153 | case naming.GRPCLB: | ||
154 | b.rbs = append(b.rbs, remoteBalancerInfo{ | ||
155 | addr: update.Addr, | ||
156 | name: md.ServerName, | ||
157 | }) | ||
158 | default: | ||
159 | grpclog.Errorf("Received unknow address type %d", md.AddrType) | ||
160 | continue | ||
161 | } | ||
162 | case naming.Delete: | ||
163 | for i, v := range b.rbs { | ||
164 | if update.Addr == v.addr { | ||
165 | copy(b.rbs[i:], b.rbs[i+1:]) | ||
166 | b.rbs = b.rbs[:len(b.rbs)-1] | ||
167 | break | ||
168 | } | ||
169 | } | ||
170 | default: | ||
171 | grpclog.Errorf("Unknown update.Op %v", update.Op) | ||
172 | } | ||
173 | } | ||
174 | // TODO: Fall back to the basic round-robin load balancing if the resulting address is | ||
175 | // not a load balancer. | ||
176 | select { | ||
177 | case <-ch: | ||
178 | default: | ||
179 | } | ||
180 | ch <- b.rbs | ||
181 | return nil | ||
182 | } | ||
183 | |||
184 | func (b *balancer) serverListExpire(seq int) { | ||
185 | b.mu.Lock() | ||
186 | defer b.mu.Unlock() | ||
187 | // TODO: gRPC interanls do not clear the connections when the server list is stale. | ||
188 | // This means RPCs will keep using the existing server list until b receives new | ||
189 | // server list even though the list is expired. Revisit this behavior later. | ||
190 | if b.done || seq < b.seq { | ||
191 | return | ||
192 | } | ||
193 | b.next = 0 | ||
194 | b.addrs = nil | ||
195 | // Ask grpc internals to close all the corresponding connections. | ||
196 | b.addrCh <- nil | ||
197 | } | ||
198 | |||
199 | func convertDuration(d *lbpb.Duration) time.Duration { | ||
200 | if d == nil { | ||
201 | return 0 | ||
202 | } | ||
203 | return time.Duration(d.Seconds)*time.Second + time.Duration(d.Nanos)*time.Nanosecond | ||
204 | } | ||
205 | |||
206 | func (b *balancer) processServerList(l *lbpb.ServerList, seq int) { | ||
207 | if l == nil { | ||
208 | return | ||
209 | } | ||
210 | servers := l.GetServers() | ||
211 | expiration := convertDuration(l.GetExpirationInterval()) | ||
212 | var ( | ||
213 | sl []*grpclbAddrInfo | ||
214 | addrs []Address | ||
215 | ) | ||
216 | for _, s := range servers { | ||
217 | md := metadata.Pairs("lb-token", s.LoadBalanceToken) | ||
218 | ip := net.IP(s.IpAddress) | ||
219 | ipStr := ip.String() | ||
220 | if ip.To4() == nil { | ||
221 | // Add square brackets to ipv6 addresses, otherwise net.Dial() and | ||
222 | // net.SplitHostPort() will return too many colons error. | ||
223 | ipStr = fmt.Sprintf("[%s]", ipStr) | ||
224 | } | ||
225 | addr := Address{ | ||
226 | Addr: fmt.Sprintf("%s:%d", ipStr, s.Port), | ||
227 | Metadata: &md, | ||
228 | } | ||
229 | sl = append(sl, &grpclbAddrInfo{ | ||
230 | addr: addr, | ||
231 | dropForRateLimiting: s.DropForRateLimiting, | ||
232 | dropForLoadBalancing: s.DropForLoadBalancing, | ||
233 | }) | ||
234 | addrs = append(addrs, addr) | ||
235 | } | ||
236 | b.mu.Lock() | ||
237 | defer b.mu.Unlock() | ||
238 | if b.done || seq < b.seq { | ||
239 | return | ||
240 | } | ||
241 | if len(sl) > 0 { | ||
242 | // reset b.next to 0 when replacing the server list. | ||
243 | b.next = 0 | ||
244 | b.addrs = sl | ||
245 | b.addrCh <- addrs | ||
246 | if b.expTimer != nil { | ||
247 | b.expTimer.Stop() | ||
248 | b.expTimer = nil | ||
249 | } | ||
250 | if expiration > 0 { | ||
251 | b.expTimer = time.AfterFunc(expiration, func() { | ||
252 | b.serverListExpire(seq) | ||
253 | }) | ||
254 | } | ||
255 | } | ||
256 | return | ||
257 | } | ||
258 | |||
259 | func (b *balancer) sendLoadReport(s *balanceLoadClientStream, interval time.Duration, done <-chan struct{}) { | ||
260 | ticker := time.NewTicker(interval) | ||
261 | defer ticker.Stop() | ||
262 | for { | ||
263 | select { | ||
264 | case <-ticker.C: | ||
265 | case <-done: | ||
266 | return | ||
267 | } | ||
268 | b.mu.Lock() | ||
269 | stats := b.clientStats | ||
270 | b.clientStats = lbpb.ClientStats{} // Clear the stats. | ||
271 | b.mu.Unlock() | ||
272 | t := time.Now() | ||
273 | stats.Timestamp = &lbpb.Timestamp{ | ||
274 | Seconds: t.Unix(), | ||
275 | Nanos: int32(t.Nanosecond()), | ||
276 | } | ||
277 | if err := s.Send(&lbpb.LoadBalanceRequest{ | ||
278 | LoadBalanceRequestType: &lbpb.LoadBalanceRequest_ClientStats{ | ||
279 | ClientStats: &stats, | ||
280 | }, | ||
281 | }); err != nil { | ||
282 | grpclog.Errorf("grpclb: failed to send load report: %v", err) | ||
283 | return | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | func (b *balancer) callRemoteBalancer(lbc *loadBalancerClient, seq int) (retry bool) { | ||
289 | ctx, cancel := context.WithCancel(context.Background()) | ||
290 | defer cancel() | ||
291 | stream, err := lbc.BalanceLoad(ctx) | ||
292 | if err != nil { | ||
293 | grpclog.Errorf("grpclb: failed to perform RPC to the remote balancer %v", err) | ||
294 | return | ||
295 | } | ||
296 | b.mu.Lock() | ||
297 | if b.done { | ||
298 | b.mu.Unlock() | ||
299 | return | ||
300 | } | ||
301 | b.mu.Unlock() | ||
302 | initReq := &lbpb.LoadBalanceRequest{ | ||
303 | LoadBalanceRequestType: &lbpb.LoadBalanceRequest_InitialRequest{ | ||
304 | InitialRequest: &lbpb.InitialLoadBalanceRequest{ | ||
305 | Name: b.target, | ||
306 | }, | ||
307 | }, | ||
308 | } | ||
309 | if err := stream.Send(initReq); err != nil { | ||
310 | grpclog.Errorf("grpclb: failed to send init request: %v", err) | ||
311 | // TODO: backoff on retry? | ||
312 | return true | ||
313 | } | ||
314 | reply, err := stream.Recv() | ||
315 | if err != nil { | ||
316 | grpclog.Errorf("grpclb: failed to recv init response: %v", err) | ||
317 | // TODO: backoff on retry? | ||
318 | return true | ||
319 | } | ||
320 | initResp := reply.GetInitialResponse() | ||
321 | if initResp == nil { | ||
322 | grpclog.Errorf("grpclb: reply from remote balancer did not include initial response.") | ||
323 | return | ||
324 | } | ||
325 | // TODO: Support delegation. | ||
326 | if initResp.LoadBalancerDelegate != "" { | ||
327 | // delegation | ||
328 | grpclog.Errorf("TODO: Delegation is not supported yet.") | ||
329 | return | ||
330 | } | ||
331 | streamDone := make(chan struct{}) | ||
332 | defer close(streamDone) | ||
333 | b.mu.Lock() | ||
334 | b.clientStats = lbpb.ClientStats{} // Clear client stats. | ||
335 | b.mu.Unlock() | ||
336 | if d := convertDuration(initResp.ClientStatsReportInterval); d > 0 { | ||
337 | go b.sendLoadReport(stream, d, streamDone) | ||
338 | } | ||
339 | // Retrieve the server list. | ||
340 | for { | ||
341 | reply, err := stream.Recv() | ||
342 | if err != nil { | ||
343 | grpclog.Errorf("grpclb: failed to recv server list: %v", err) | ||
344 | break | ||
345 | } | ||
346 | b.mu.Lock() | ||
347 | if b.done || seq < b.seq { | ||
348 | b.mu.Unlock() | ||
349 | return | ||
350 | } | ||
351 | b.seq++ // tick when receiving a new list of servers. | ||
352 | seq = b.seq | ||
353 | b.mu.Unlock() | ||
354 | if serverList := reply.GetServerList(); serverList != nil { | ||
355 | b.processServerList(serverList, seq) | ||
356 | } | ||
357 | } | ||
358 | return true | ||
359 | } | ||
360 | |||
361 | func (b *balancer) Start(target string, config BalancerConfig) error { | ||
362 | b.rand = rand.New(rand.NewSource(time.Now().Unix())) | ||
363 | // TODO: Fall back to the basic direct connection if there is no name resolver. | ||
364 | if b.r == nil { | ||
365 | return errors.New("there is no name resolver installed") | ||
366 | } | ||
367 | b.target = target | ||
368 | b.mu.Lock() | ||
369 | if b.done { | ||
370 | b.mu.Unlock() | ||
371 | return ErrClientConnClosing | ||
372 | } | ||
373 | b.addrCh = make(chan []Address) | ||
374 | w, err := b.r.Resolve(target) | ||
375 | if err != nil { | ||
376 | b.mu.Unlock() | ||
377 | grpclog.Errorf("grpclb: failed to resolve address: %v, err: %v", target, err) | ||
378 | return err | ||
379 | } | ||
380 | b.w = w | ||
381 | b.mu.Unlock() | ||
382 | balancerAddrsCh := make(chan []remoteBalancerInfo, 1) | ||
383 | // Spawn a goroutine to monitor the name resolution of remote load balancer. | ||
384 | go func() { | ||
385 | for { | ||
386 | if err := b.watchAddrUpdates(w, balancerAddrsCh); err != nil { | ||
387 | grpclog.Warningf("grpclb: the naming watcher stops working due to %v.\n", err) | ||
388 | close(balancerAddrsCh) | ||
389 | return | ||
390 | } | ||
391 | } | ||
392 | }() | ||
393 | // Spawn a goroutine to talk to the remote load balancer. | ||
394 | go func() { | ||
395 | var ( | ||
396 | cc *ClientConn | ||
397 | // ccError is closed when there is an error in the current cc. | ||
398 | // A new rb should be picked from rbs and connected. | ||
399 | ccError chan struct{} | ||
400 | rb *remoteBalancerInfo | ||
401 | rbs []remoteBalancerInfo | ||
402 | rbIdx int | ||
403 | ) | ||
404 | |||
405 | defer func() { | ||
406 | if ccError != nil { | ||
407 | select { | ||
408 | case <-ccError: | ||
409 | default: | ||
410 | close(ccError) | ||
411 | } | ||
412 | } | ||
413 | if cc != nil { | ||
414 | cc.Close() | ||
415 | } | ||
416 | }() | ||
417 | |||
418 | for { | ||
419 | var ok bool | ||
420 | select { | ||
421 | case rbs, ok = <-balancerAddrsCh: | ||
422 | if !ok { | ||
423 | return | ||
424 | } | ||
425 | foundIdx := -1 | ||
426 | if rb != nil { | ||
427 | for i, trb := range rbs { | ||
428 | if trb == *rb { | ||
429 | foundIdx = i | ||
430 | break | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | if foundIdx >= 0 { | ||
435 | if foundIdx >= 1 { | ||
436 | // Move the address in use to the beginning of the list. | ||
437 | b.rbs[0], b.rbs[foundIdx] = b.rbs[foundIdx], b.rbs[0] | ||
438 | rbIdx = 0 | ||
439 | } | ||
440 | continue // If found, don't dial new cc. | ||
441 | } else if len(rbs) > 0 { | ||
442 | // Pick a random one from the list, instead of always using the first one. | ||
443 | if l := len(rbs); l > 1 && rb != nil { | ||
444 | tmpIdx := b.rand.Intn(l - 1) | ||
445 | b.rbs[0], b.rbs[tmpIdx] = b.rbs[tmpIdx], b.rbs[0] | ||
446 | } | ||
447 | rbIdx = 0 | ||
448 | rb = &rbs[0] | ||
449 | } else { | ||
450 | // foundIdx < 0 && len(rbs) <= 0. | ||
451 | rb = nil | ||
452 | } | ||
453 | case <-ccError: | ||
454 | ccError = nil | ||
455 | if rbIdx < len(rbs)-1 { | ||
456 | rbIdx++ | ||
457 | rb = &rbs[rbIdx] | ||
458 | } else { | ||
459 | rb = nil | ||
460 | } | ||
461 | } | ||
462 | |||
463 | if rb == nil { | ||
464 | continue | ||
465 | } | ||
466 | |||
467 | if cc != nil { | ||
468 | cc.Close() | ||
469 | } | ||
470 | // Talk to the remote load balancer to get the server list. | ||
471 | var ( | ||
472 | err error | ||
473 | dopts []DialOption | ||
474 | ) | ||
475 | if creds := config.DialCreds; creds != nil { | ||
476 | if rb.name != "" { | ||
477 | if err := creds.OverrideServerName(rb.name); err != nil { | ||
478 | grpclog.Warningf("grpclb: failed to override the server name in the credentials: %v", err) | ||
479 | continue | ||
480 | } | ||
481 | } | ||
482 | dopts = append(dopts, WithTransportCredentials(creds)) | ||
483 | } else { | ||
484 | dopts = append(dopts, WithInsecure()) | ||
485 | } | ||
486 | if dialer := config.Dialer; dialer != nil { | ||
487 | // WithDialer takes a different type of function, so we instead use a special DialOption here. | ||
488 | dopts = append(dopts, func(o *dialOptions) { o.copts.Dialer = dialer }) | ||
489 | } | ||
490 | ccError = make(chan struct{}) | ||
491 | cc, err = Dial(rb.addr, dopts...) | ||
492 | if err != nil { | ||
493 | grpclog.Warningf("grpclb: failed to setup a connection to the remote balancer %v: %v", rb.addr, err) | ||
494 | close(ccError) | ||
495 | continue | ||
496 | } | ||
497 | b.mu.Lock() | ||
498 | b.seq++ // tick when getting a new balancer address | ||
499 | seq := b.seq | ||
500 | b.next = 0 | ||
501 | b.mu.Unlock() | ||
502 | go func(cc *ClientConn, ccError chan struct{}) { | ||
503 | lbc := &loadBalancerClient{cc} | ||
504 | b.callRemoteBalancer(lbc, seq) | ||
505 | cc.Close() | ||
506 | select { | ||
507 | case <-ccError: | ||
508 | default: | ||
509 | close(ccError) | ||
510 | } | ||
511 | }(cc, ccError) | ||
512 | } | ||
513 | }() | ||
514 | return nil | ||
515 | } | ||
516 | |||
517 | func (b *balancer) down(addr Address, err error) { | ||
518 | b.mu.Lock() | ||
519 | defer b.mu.Unlock() | ||
520 | for _, a := range b.addrs { | ||
521 | if addr == a.addr { | ||
522 | a.connected = false | ||
523 | break | ||
524 | } | ||
525 | } | ||
526 | } | ||
527 | |||
528 | func (b *balancer) Up(addr Address) func(error) { | ||
529 | b.mu.Lock() | ||
530 | defer b.mu.Unlock() | ||
531 | if b.done { | ||
532 | return nil | ||
533 | } | ||
534 | var cnt int | ||
535 | for _, a := range b.addrs { | ||
536 | if a.addr == addr { | ||
537 | if a.connected { | ||
538 | return nil | ||
539 | } | ||
540 | a.connected = true | ||
541 | } | ||
542 | if a.connected && !a.dropForRateLimiting && !a.dropForLoadBalancing { | ||
543 | cnt++ | ||
544 | } | ||
545 | } | ||
546 | // addr is the only one which is connected. Notify the Get() callers who are blocking. | ||
547 | if cnt == 1 && b.waitCh != nil { | ||
548 | close(b.waitCh) | ||
549 | b.waitCh = nil | ||
550 | } | ||
551 | return func(err error) { | ||
552 | b.down(addr, err) | ||
553 | } | ||
554 | } | ||
555 | |||
556 | func (b *balancer) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) { | ||
557 | var ch chan struct{} | ||
558 | b.mu.Lock() | ||
559 | if b.done { | ||
560 | b.mu.Unlock() | ||
561 | err = ErrClientConnClosing | ||
562 | return | ||
563 | } | ||
564 | seq := b.seq | ||
565 | |||
566 | defer func() { | ||
567 | if err != nil { | ||
568 | return | ||
569 | } | ||
570 | put = func() { | ||
571 | s, ok := rpcInfoFromContext(ctx) | ||
572 | if !ok { | ||
573 | return | ||
574 | } | ||
575 | b.mu.Lock() | ||
576 | defer b.mu.Unlock() | ||
577 | if b.done || seq < b.seq { | ||
578 | return | ||
579 | } | ||
580 | b.clientStats.NumCallsFinished++ | ||
581 | if !s.bytesSent { | ||
582 | b.clientStats.NumCallsFinishedWithClientFailedToSend++ | ||
583 | } else if s.bytesReceived { | ||
584 | b.clientStats.NumCallsFinishedKnownReceived++ | ||
585 | } | ||
586 | } | ||
587 | }() | ||
588 | |||
589 | b.clientStats.NumCallsStarted++ | ||
590 | if len(b.addrs) > 0 { | ||
591 | if b.next >= len(b.addrs) { | ||
592 | b.next = 0 | ||
593 | } | ||
594 | next := b.next | ||
595 | for { | ||
596 | a := b.addrs[next] | ||
597 | next = (next + 1) % len(b.addrs) | ||
598 | if a.connected { | ||
599 | if !a.dropForRateLimiting && !a.dropForLoadBalancing { | ||
600 | addr = a.addr | ||
601 | b.next = next | ||
602 | b.mu.Unlock() | ||
603 | return | ||
604 | } | ||
605 | if !opts.BlockingWait { | ||
606 | b.next = next | ||
607 | if a.dropForLoadBalancing { | ||
608 | b.clientStats.NumCallsFinished++ | ||
609 | b.clientStats.NumCallsFinishedWithDropForLoadBalancing++ | ||
610 | } else if a.dropForRateLimiting { | ||
611 | b.clientStats.NumCallsFinished++ | ||
612 | b.clientStats.NumCallsFinishedWithDropForRateLimiting++ | ||
613 | } | ||
614 | b.mu.Unlock() | ||
615 | err = Errorf(codes.Unavailable, "%s drops requests", a.addr.Addr) | ||
616 | return | ||
617 | } | ||
618 | } | ||
619 | if next == b.next { | ||
620 | // Has iterated all the possible address but none is connected. | ||
621 | break | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | if !opts.BlockingWait { | ||
626 | if len(b.addrs) == 0 { | ||
627 | b.clientStats.NumCallsFinished++ | ||
628 | b.clientStats.NumCallsFinishedWithClientFailedToSend++ | ||
629 | b.mu.Unlock() | ||
630 | err = Errorf(codes.Unavailable, "there is no address available") | ||
631 | return | ||
632 | } | ||
633 | // Returns the next addr on b.addrs for a failfast RPC. | ||
634 | addr = b.addrs[b.next].addr | ||
635 | b.next++ | ||
636 | b.mu.Unlock() | ||
637 | return | ||
638 | } | ||
639 | // Wait on b.waitCh for non-failfast RPCs. | ||
640 | if b.waitCh == nil { | ||
641 | ch = make(chan struct{}) | ||
642 | b.waitCh = ch | ||
643 | } else { | ||
644 | ch = b.waitCh | ||
645 | } | ||
646 | b.mu.Unlock() | ||
647 | for { | ||
648 | select { | ||
649 | case <-ctx.Done(): | ||
650 | b.mu.Lock() | ||
651 | b.clientStats.NumCallsFinished++ | ||
652 | b.clientStats.NumCallsFinishedWithClientFailedToSend++ | ||
653 | b.mu.Unlock() | ||
654 | err = ctx.Err() | ||
655 | return | ||
656 | case <-ch: | ||
657 | b.mu.Lock() | ||
658 | if b.done { | ||
659 | b.clientStats.NumCallsFinished++ | ||
660 | b.clientStats.NumCallsFinishedWithClientFailedToSend++ | ||
661 | b.mu.Unlock() | ||
662 | err = ErrClientConnClosing | ||
663 | return | ||
664 | } | ||
665 | |||
666 | if len(b.addrs) > 0 { | ||
667 | if b.next >= len(b.addrs) { | ||
668 | b.next = 0 | ||
669 | } | ||
670 | next := b.next | ||
671 | for { | ||
672 | a := b.addrs[next] | ||
673 | next = (next + 1) % len(b.addrs) | ||
674 | if a.connected { | ||
675 | if !a.dropForRateLimiting && !a.dropForLoadBalancing { | ||
676 | addr = a.addr | ||
677 | b.next = next | ||
678 | b.mu.Unlock() | ||
679 | return | ||
680 | } | ||
681 | if !opts.BlockingWait { | ||
682 | b.next = next | ||
683 | if a.dropForLoadBalancing { | ||
684 | b.clientStats.NumCallsFinished++ | ||
685 | b.clientStats.NumCallsFinishedWithDropForLoadBalancing++ | ||
686 | } else if a.dropForRateLimiting { | ||
687 | b.clientStats.NumCallsFinished++ | ||
688 | b.clientStats.NumCallsFinishedWithDropForRateLimiting++ | ||
689 | } | ||
690 | b.mu.Unlock() | ||
691 | err = Errorf(codes.Unavailable, "drop requests for the addreess %s", a.addr.Addr) | ||
692 | return | ||
693 | } | ||
694 | } | ||
695 | if next == b.next { | ||
696 | // Has iterated all the possible address but none is connected. | ||
697 | break | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | // The newly added addr got removed by Down() again. | ||
702 | if b.waitCh == nil { | ||
703 | ch = make(chan struct{}) | ||
704 | b.waitCh = ch | ||
705 | } else { | ||
706 | ch = b.waitCh | ||
707 | } | ||
708 | b.mu.Unlock() | ||
709 | } | ||
710 | } | ||
711 | } | ||
712 | |||
713 | func (b *balancer) Notify() <-chan []Address { | ||
714 | return b.addrCh | ||
715 | } | ||
716 | |||
717 | func (b *balancer) Close() error { | ||
718 | b.mu.Lock() | ||
719 | defer b.mu.Unlock() | ||
720 | if b.done { | ||
721 | return errBalancerClosed | ||
722 | } | ||
723 | b.done = true | ||
724 | if b.expTimer != nil { | ||
725 | b.expTimer.Stop() | ||
726 | } | ||
727 | if b.waitCh != nil { | ||
728 | close(b.waitCh) | ||
729 | } | ||
730 | if b.addrCh != nil { | ||
731 | close(b.addrCh) | ||
732 | } | ||
733 | if b.w != nil { | ||
734 | b.w.Close() | ||
735 | } | ||
736 | return nil | ||
737 | } | ||
diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.pb.go b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.pb.go deleted file mode 100644 index f63941b..0000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.pb.go +++ /dev/null | |||
@@ -1,629 +0,0 @@ | |||
1 | // Code generated by protoc-gen-go. | ||
2 | // source: grpclb.proto | ||
3 | // DO NOT EDIT! | ||
4 | |||
5 | /* | ||
6 | Package grpc_lb_v1 is a generated protocol buffer package. | ||
7 | |||
8 | It is generated from these files: | ||
9 | grpclb.proto | ||
10 | |||
11 | It has these top-level messages: | ||
12 | Duration | ||
13 | Timestamp | ||
14 | LoadBalanceRequest | ||
15 | InitialLoadBalanceRequest | ||
16 | ClientStats | ||
17 | LoadBalanceResponse | ||
18 | InitialLoadBalanceResponse | ||
19 | ServerList | ||
20 | Server | ||
21 | */ | ||
22 | package grpc_lb_v1 | ||
23 | |||
24 | import proto "github.com/golang/protobuf/proto" | ||
25 | import fmt "fmt" | ||
26 | import math "math" | ||
27 | |||
28 | // Reference imports to suppress errors if they are not otherwise used. | ||
29 | var _ = proto.Marshal | ||
30 | var _ = fmt.Errorf | ||
31 | var _ = math.Inf | ||
32 | |||
33 | // This is a compile-time assertion to ensure that this generated file | ||
34 | // is compatible with the proto package it is being compiled against. | ||
35 | // A compilation error at this line likely means your copy of the | ||
36 | // proto package needs to be updated. | ||
37 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||
38 | |||
39 | type Duration struct { | ||
40 | // Signed seconds of the span of time. Must be from -315,576,000,000 | ||
41 | // to +315,576,000,000 inclusive. | ||
42 | Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` | ||
43 | // Signed fractions of a second at nanosecond resolution of the span | ||
44 | // of time. Durations less than one second are represented with a 0 | ||
45 | // `seconds` field and a positive or negative `nanos` field. For durations | ||
46 | // of one second or more, a non-zero value for the `nanos` field must be | ||
47 | // of the same sign as the `seconds` field. Must be from -999,999,999 | ||
48 | // to +999,999,999 inclusive. | ||
49 | Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` | ||
50 | } | ||
51 | |||
52 | func (m *Duration) Reset() { *m = Duration{} } | ||
53 | func (m *Duration) String() string { return proto.CompactTextString(m) } | ||
54 | func (*Duration) ProtoMessage() {} | ||
55 | func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } | ||
56 | |||
57 | func (m *Duration) GetSeconds() int64 { | ||
58 | if m != nil { | ||
59 | return m.Seconds | ||
60 | } | ||
61 | return 0 | ||
62 | } | ||
63 | |||
64 | func (m *Duration) GetNanos() int32 { | ||
65 | if m != nil { | ||
66 | return m.Nanos | ||
67 | } | ||
68 | return 0 | ||
69 | } | ||
70 | |||
71 | type Timestamp struct { | ||
72 | // Represents seconds of UTC time since Unix epoch | ||
73 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to | ||
74 | // 9999-12-31T23:59:59Z inclusive. | ||
75 | Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` | ||
76 | // Non-negative fractions of a second at nanosecond resolution. Negative | ||
77 | // second values with fractions must still have non-negative nanos values | ||
78 | // that count forward in time. Must be from 0 to 999,999,999 | ||
79 | // inclusive. | ||
80 | Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` | ||
81 | } | ||
82 | |||
83 | func (m *Timestamp) Reset() { *m = Timestamp{} } | ||
84 | func (m *Timestamp) String() string { return proto.CompactTextString(m) } | ||
85 | func (*Timestamp) ProtoMessage() {} | ||
86 | func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } | ||
87 | |||
88 | func (m *Timestamp) GetSeconds() int64 { | ||
89 | if m != nil { | ||
90 | return m.Seconds | ||
91 | } | ||
92 | return 0 | ||
93 | } | ||
94 | |||
95 | func (m *Timestamp) GetNanos() int32 { | ||
96 | if m != nil { | ||
97 | return m.Nanos | ||
98 | } | ||
99 | return 0 | ||
100 | } | ||
101 | |||
102 | type LoadBalanceRequest struct { | ||
103 | // Types that are valid to be assigned to LoadBalanceRequestType: | ||
104 | // *LoadBalanceRequest_InitialRequest | ||
105 | // *LoadBalanceRequest_ClientStats | ||
106 | LoadBalanceRequestType isLoadBalanceRequest_LoadBalanceRequestType `protobuf_oneof:"load_balance_request_type"` | ||
107 | } | ||
108 | |||
109 | func (m *LoadBalanceRequest) Reset() { *m = LoadBalanceRequest{} } | ||
110 | func (m *LoadBalanceRequest) String() string { return proto.CompactTextString(m) } | ||
111 | func (*LoadBalanceRequest) ProtoMessage() {} | ||
112 | func (*LoadBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } | ||
113 | |||
114 | type isLoadBalanceRequest_LoadBalanceRequestType interface { | ||
115 | isLoadBalanceRequest_LoadBalanceRequestType() | ||
116 | } | ||
117 | |||
118 | type LoadBalanceRequest_InitialRequest struct { | ||
119 | InitialRequest *InitialLoadBalanceRequest `protobuf:"bytes,1,opt,name=initial_request,json=initialRequest,oneof"` | ||
120 | } | ||
121 | type LoadBalanceRequest_ClientStats struct { | ||
122 | ClientStats *ClientStats `protobuf:"bytes,2,opt,name=client_stats,json=clientStats,oneof"` | ||
123 | } | ||
124 | |||
125 | func (*LoadBalanceRequest_InitialRequest) isLoadBalanceRequest_LoadBalanceRequestType() {} | ||
126 | func (*LoadBalanceRequest_ClientStats) isLoadBalanceRequest_LoadBalanceRequestType() {} | ||
127 | |||
128 | func (m *LoadBalanceRequest) GetLoadBalanceRequestType() isLoadBalanceRequest_LoadBalanceRequestType { | ||
129 | if m != nil { | ||
130 | return m.LoadBalanceRequestType | ||
131 | } | ||
132 | return nil | ||
133 | } | ||
134 | |||
135 | func (m *LoadBalanceRequest) GetInitialRequest() *InitialLoadBalanceRequest { | ||
136 | if x, ok := m.GetLoadBalanceRequestType().(*LoadBalanceRequest_InitialRequest); ok { | ||
137 | return x.InitialRequest | ||
138 | } | ||
139 | return nil | ||
140 | } | ||
141 | |||
142 | func (m *LoadBalanceRequest) GetClientStats() *ClientStats { | ||
143 | if x, ok := m.GetLoadBalanceRequestType().(*LoadBalanceRequest_ClientStats); ok { | ||
144 | return x.ClientStats | ||
145 | } | ||
146 | return nil | ||
147 | } | ||
148 | |||
149 | // XXX_OneofFuncs is for the internal use of the proto package. | ||
150 | func (*LoadBalanceRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { | ||
151 | return _LoadBalanceRequest_OneofMarshaler, _LoadBalanceRequest_OneofUnmarshaler, _LoadBalanceRequest_OneofSizer, []interface{}{ | ||
152 | (*LoadBalanceRequest_InitialRequest)(nil), | ||
153 | (*LoadBalanceRequest_ClientStats)(nil), | ||
154 | } | ||
155 | } | ||
156 | |||
157 | func _LoadBalanceRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { | ||
158 | m := msg.(*LoadBalanceRequest) | ||
159 | // load_balance_request_type | ||
160 | switch x := m.LoadBalanceRequestType.(type) { | ||
161 | case *LoadBalanceRequest_InitialRequest: | ||
162 | b.EncodeVarint(1<<3 | proto.WireBytes) | ||
163 | if err := b.EncodeMessage(x.InitialRequest); err != nil { | ||
164 | return err | ||
165 | } | ||
166 | case *LoadBalanceRequest_ClientStats: | ||
167 | b.EncodeVarint(2<<3 | proto.WireBytes) | ||
168 | if err := b.EncodeMessage(x.ClientStats); err != nil { | ||
169 | return err | ||
170 | } | ||
171 | case nil: | ||
172 | default: | ||
173 | return fmt.Errorf("LoadBalanceRequest.LoadBalanceRequestType has unexpected type %T", x) | ||
174 | } | ||
175 | return nil | ||
176 | } | ||
177 | |||
178 | func _LoadBalanceRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { | ||
179 | m := msg.(*LoadBalanceRequest) | ||
180 | switch tag { | ||
181 | case 1: // load_balance_request_type.initial_request | ||
182 | if wire != proto.WireBytes { | ||
183 | return true, proto.ErrInternalBadWireType | ||
184 | } | ||
185 | msg := new(InitialLoadBalanceRequest) | ||
186 | err := b.DecodeMessage(msg) | ||
187 | m.LoadBalanceRequestType = &LoadBalanceRequest_InitialRequest{msg} | ||
188 | return true, err | ||
189 | case 2: // load_balance_request_type.client_stats | ||
190 | if wire != proto.WireBytes { | ||
191 | return true, proto.ErrInternalBadWireType | ||
192 | } | ||
193 | msg := new(ClientStats) | ||
194 | err := b.DecodeMessage(msg) | ||
195 | m.LoadBalanceRequestType = &LoadBalanceRequest_ClientStats{msg} | ||
196 | return true, err | ||
197 | default: | ||
198 | return false, nil | ||
199 | } | ||
200 | } | ||
201 | |||
202 | func _LoadBalanceRequest_OneofSizer(msg proto.Message) (n int) { | ||
203 | m := msg.(*LoadBalanceRequest) | ||
204 | // load_balance_request_type | ||
205 | switch x := m.LoadBalanceRequestType.(type) { | ||
206 | case *LoadBalanceRequest_InitialRequest: | ||
207 | s := proto.Size(x.InitialRequest) | ||
208 | n += proto.SizeVarint(1<<3 | proto.WireBytes) | ||
209 | n += proto.SizeVarint(uint64(s)) | ||
210 | n += s | ||
211 | case *LoadBalanceRequest_ClientStats: | ||
212 | s := proto.Size(x.ClientStats) | ||
213 | n += proto.SizeVarint(2<<3 | proto.WireBytes) | ||
214 | n += proto.SizeVarint(uint64(s)) | ||
215 | n += s | ||
216 | case nil: | ||
217 | default: | ||
218 | panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) | ||
219 | } | ||
220 | return n | ||
221 | } | ||
222 | |||
223 | type InitialLoadBalanceRequest struct { | ||
224 | // Name of load balanced service (IE, balancer.service.com) | ||
225 | // length should be less than 256 bytes. | ||
226 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` | ||
227 | } | ||
228 | |||
229 | func (m *InitialLoadBalanceRequest) Reset() { *m = InitialLoadBalanceRequest{} } | ||
230 | func (m *InitialLoadBalanceRequest) String() string { return proto.CompactTextString(m) } | ||
231 | func (*InitialLoadBalanceRequest) ProtoMessage() {} | ||
232 | func (*InitialLoadBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } | ||
233 | |||
234 | func (m *InitialLoadBalanceRequest) GetName() string { | ||
235 | if m != nil { | ||
236 | return m.Name | ||
237 | } | ||
238 | return "" | ||
239 | } | ||
240 | |||
241 | // Contains client level statistics that are useful to load balancing. Each | ||
242 | // count except the timestamp should be reset to zero after reporting the stats. | ||
243 | type ClientStats struct { | ||
244 | // The timestamp of generating the report. | ||
245 | Timestamp *Timestamp `protobuf:"bytes,1,opt,name=timestamp" json:"timestamp,omitempty"` | ||
246 | // The total number of RPCs that started. | ||
247 | NumCallsStarted int64 `protobuf:"varint,2,opt,name=num_calls_started,json=numCallsStarted" json:"num_calls_started,omitempty"` | ||
248 | // The total number of RPCs that finished. | ||
249 | NumCallsFinished int64 `protobuf:"varint,3,opt,name=num_calls_finished,json=numCallsFinished" json:"num_calls_finished,omitempty"` | ||
250 | // The total number of RPCs that were dropped by the client because of rate | ||
251 | // limiting. | ||
252 | NumCallsFinishedWithDropForRateLimiting int64 `protobuf:"varint,4,opt,name=num_calls_finished_with_drop_for_rate_limiting,json=numCallsFinishedWithDropForRateLimiting" json:"num_calls_finished_with_drop_for_rate_limiting,omitempty"` | ||
253 | // The total number of RPCs that were dropped by the client because of load | ||
254 | // balancing. | ||
255 | NumCallsFinishedWithDropForLoadBalancing int64 `protobuf:"varint,5,opt,name=num_calls_finished_with_drop_for_load_balancing,json=numCallsFinishedWithDropForLoadBalancing" json:"num_calls_finished_with_drop_for_load_balancing,omitempty"` | ||
256 | // The total number of RPCs that failed to reach a server except dropped RPCs. | ||
257 | NumCallsFinishedWithClientFailedToSend int64 `protobuf:"varint,6,opt,name=num_calls_finished_with_client_failed_to_send,json=numCallsFinishedWithClientFailedToSend" json:"num_calls_finished_with_client_failed_to_send,omitempty"` | ||
258 | // The total number of RPCs that finished and are known to have been received | ||
259 | // by a server. | ||
260 | NumCallsFinishedKnownReceived int64 `protobuf:"varint,7,opt,name=num_calls_finished_known_received,json=numCallsFinishedKnownReceived" json:"num_calls_finished_known_received,omitempty"` | ||
261 | } | ||
262 | |||
263 | func (m *ClientStats) Reset() { *m = ClientStats{} } | ||
264 | func (m *ClientStats) String() string { return proto.CompactTextString(m) } | ||
265 | func (*ClientStats) ProtoMessage() {} | ||
266 | func (*ClientStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } | ||
267 | |||
268 | func (m *ClientStats) GetTimestamp() *Timestamp { | ||
269 | if m != nil { | ||
270 | return m.Timestamp | ||
271 | } | ||
272 | return nil | ||
273 | } | ||
274 | |||
275 | func (m *ClientStats) GetNumCallsStarted() int64 { | ||
276 | if m != nil { | ||
277 | return m.NumCallsStarted | ||
278 | } | ||
279 | return 0 | ||
280 | } | ||
281 | |||
282 | func (m *ClientStats) GetNumCallsFinished() int64 { | ||
283 | if m != nil { | ||
284 | return m.NumCallsFinished | ||
285 | } | ||
286 | return 0 | ||
287 | } | ||
288 | |||
289 | func (m *ClientStats) GetNumCallsFinishedWithDropForRateLimiting() int64 { | ||
290 | if m != nil { | ||
291 | return m.NumCallsFinishedWithDropForRateLimiting | ||
292 | } | ||
293 | return 0 | ||
294 | } | ||
295 | |||
296 | func (m *ClientStats) GetNumCallsFinishedWithDropForLoadBalancing() int64 { | ||
297 | if m != nil { | ||
298 | return m.NumCallsFinishedWithDropForLoadBalancing | ||
299 | } | ||
300 | return 0 | ||
301 | } | ||
302 | |||
303 | func (m *ClientStats) GetNumCallsFinishedWithClientFailedToSend() int64 { | ||
304 | if m != nil { | ||
305 | return m.NumCallsFinishedWithClientFailedToSend | ||
306 | } | ||
307 | return 0 | ||
308 | } | ||
309 | |||
310 | func (m *ClientStats) GetNumCallsFinishedKnownReceived() int64 { | ||
311 | if m != nil { | ||
312 | return m.NumCallsFinishedKnownReceived | ||
313 | } | ||
314 | return 0 | ||
315 | } | ||
316 | |||
317 | type LoadBalanceResponse struct { | ||
318 | // Types that are valid to be assigned to LoadBalanceResponseType: | ||
319 | // *LoadBalanceResponse_InitialResponse | ||
320 | // *LoadBalanceResponse_ServerList | ||
321 | LoadBalanceResponseType isLoadBalanceResponse_LoadBalanceResponseType `protobuf_oneof:"load_balance_response_type"` | ||
322 | } | ||
323 | |||
324 | func (m *LoadBalanceResponse) Reset() { *m = LoadBalanceResponse{} } | ||
325 | func (m *LoadBalanceResponse) String() string { return proto.CompactTextString(m) } | ||
326 | func (*LoadBalanceResponse) ProtoMessage() {} | ||
327 | func (*LoadBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } | ||
328 | |||
329 | type isLoadBalanceResponse_LoadBalanceResponseType interface { | ||
330 | isLoadBalanceResponse_LoadBalanceResponseType() | ||
331 | } | ||
332 | |||
333 | type LoadBalanceResponse_InitialResponse struct { | ||
334 | InitialResponse *InitialLoadBalanceResponse `protobuf:"bytes,1,opt,name=initial_response,json=initialResponse,oneof"` | ||
335 | } | ||
336 | type LoadBalanceResponse_ServerList struct { | ||
337 | ServerList *ServerList `protobuf:"bytes,2,opt,name=server_list,json=serverList,oneof"` | ||
338 | } | ||
339 | |||
340 | func (*LoadBalanceResponse_InitialResponse) isLoadBalanceResponse_LoadBalanceResponseType() {} | ||
341 | func (*LoadBalanceResponse_ServerList) isLoadBalanceResponse_LoadBalanceResponseType() {} | ||
342 | |||
343 | func (m *LoadBalanceResponse) GetLoadBalanceResponseType() isLoadBalanceResponse_LoadBalanceResponseType { | ||
344 | if m != nil { | ||
345 | return m.LoadBalanceResponseType | ||
346 | } | ||
347 | return nil | ||
348 | } | ||
349 | |||
350 | func (m *LoadBalanceResponse) GetInitialResponse() *InitialLoadBalanceResponse { | ||
351 | if x, ok := m.GetLoadBalanceResponseType().(*LoadBalanceResponse_InitialResponse); ok { | ||
352 | return x.InitialResponse | ||
353 | } | ||
354 | return nil | ||
355 | } | ||
356 | |||
357 | func (m *LoadBalanceResponse) GetServerList() *ServerList { | ||
358 | if x, ok := m.GetLoadBalanceResponseType().(*LoadBalanceResponse_ServerList); ok { | ||
359 | return x.ServerList | ||
360 | } | ||
361 | return nil | ||
362 | } | ||
363 | |||
364 | // XXX_OneofFuncs is for the internal use of the proto package. | ||
365 | func (*LoadBalanceResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { | ||
366 | return _LoadBalanceResponse_OneofMarshaler, _LoadBalanceResponse_OneofUnmarshaler, _LoadBalanceResponse_OneofSizer, []interface{}{ | ||
367 | (*LoadBalanceResponse_InitialResponse)(nil), | ||
368 | (*LoadBalanceResponse_ServerList)(nil), | ||
369 | } | ||
370 | } | ||
371 | |||
372 | func _LoadBalanceResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { | ||
373 | m := msg.(*LoadBalanceResponse) | ||
374 | // load_balance_response_type | ||
375 | switch x := m.LoadBalanceResponseType.(type) { | ||
376 | case *LoadBalanceResponse_InitialResponse: | ||
377 | b.EncodeVarint(1<<3 | proto.WireBytes) | ||
378 | if err := b.EncodeMessage(x.InitialResponse); err != nil { | ||
379 | return err | ||
380 | } | ||
381 | case *LoadBalanceResponse_ServerList: | ||
382 | b.EncodeVarint(2<<3 | proto.WireBytes) | ||
383 | if err := b.EncodeMessage(x.ServerList); err != nil { | ||
384 | return err | ||
385 | } | ||
386 | case nil: | ||
387 | default: | ||
388 | return fmt.Errorf("LoadBalanceResponse.LoadBalanceResponseType has unexpected type %T", x) | ||
389 | } | ||
390 | return nil | ||
391 | } | ||
392 | |||
393 | func _LoadBalanceResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { | ||
394 | m := msg.(*LoadBalanceResponse) | ||
395 | switch tag { | ||
396 | case 1: // load_balance_response_type.initial_response | ||
397 | if wire != proto.WireBytes { | ||
398 | return true, proto.ErrInternalBadWireType | ||
399 | } | ||
400 | msg := new(InitialLoadBalanceResponse) | ||
401 | err := b.DecodeMessage(msg) | ||
402 | m.LoadBalanceResponseType = &LoadBalanceResponse_InitialResponse{msg} | ||
403 | return true, err | ||
404 | case 2: // load_balance_response_type.server_list | ||
405 | if wire != proto.WireBytes { | ||
406 | return true, proto.ErrInternalBadWireType | ||
407 | } | ||
408 | msg := new(ServerList) | ||
409 | err := b.DecodeMessage(msg) | ||
410 | m.LoadBalanceResponseType = &LoadBalanceResponse_ServerList{msg} | ||
411 | return true, err | ||
412 | default: | ||
413 | return false, nil | ||
414 | } | ||
415 | } | ||
416 | |||
417 | func _LoadBalanceResponse_OneofSizer(msg proto.Message) (n int) { | ||
418 | m := msg.(*LoadBalanceResponse) | ||
419 | // load_balance_response_type | ||
420 | switch x := m.LoadBalanceResponseType.(type) { | ||
421 | case *LoadBalanceResponse_InitialResponse: | ||
422 | s := proto.Size(x.InitialResponse) | ||
423 | n += proto.SizeVarint(1<<3 | proto.WireBytes) | ||
424 | n += proto.SizeVarint(uint64(s)) | ||
425 | n += s | ||
426 | case *LoadBalanceResponse_ServerList: | ||
427 | s := proto.Size(x.ServerList) | ||
428 | n += proto.SizeVarint(2<<3 | proto.WireBytes) | ||
429 | n += proto.SizeVarint(uint64(s)) | ||
430 | n += s | ||
431 | case nil: | ||
432 | default: | ||
433 | panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) | ||
434 | } | ||
435 | return n | ||
436 | } | ||
437 | |||
438 | type InitialLoadBalanceResponse struct { | ||
439 | // This is an application layer redirect that indicates the client should use | ||
440 | // the specified server for load balancing. When this field is non-empty in | ||
441 | // the response, the client should open a separate connection to the | ||
442 | // load_balancer_delegate and call the BalanceLoad method. Its length should | ||
443 | // be less than 64 bytes. | ||
444 | LoadBalancerDelegate string `protobuf:"bytes,1,opt,name=load_balancer_delegate,json=loadBalancerDelegate" json:"load_balancer_delegate,omitempty"` | ||
445 | // This interval defines how often the client should send the client stats | ||
446 | // to the load balancer. Stats should only be reported when the duration is | ||
447 | // positive. | ||
448 | ClientStatsReportInterval *Duration `protobuf:"bytes,2,opt,name=client_stats_report_interval,json=clientStatsReportInterval" json:"client_stats_report_interval,omitempty"` | ||
449 | } | ||
450 | |||
451 | func (m *InitialLoadBalanceResponse) Reset() { *m = InitialLoadBalanceResponse{} } | ||
452 | func (m *InitialLoadBalanceResponse) String() string { return proto.CompactTextString(m) } | ||
453 | func (*InitialLoadBalanceResponse) ProtoMessage() {} | ||
454 | func (*InitialLoadBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } | ||
455 | |||
456 | func (m *InitialLoadBalanceResponse) GetLoadBalancerDelegate() string { | ||
457 | if m != nil { | ||
458 | return m.LoadBalancerDelegate | ||
459 | } | ||
460 | return "" | ||
461 | } | ||
462 | |||
463 | func (m *InitialLoadBalanceResponse) GetClientStatsReportInterval() *Duration { | ||
464 | if m != nil { | ||
465 | return m.ClientStatsReportInterval | ||
466 | } | ||
467 | return nil | ||
468 | } | ||
469 | |||
470 | type ServerList struct { | ||
471 | // Contains a list of servers selected by the load balancer. The list will | ||
472 | // be updated when server resolutions change or as needed to balance load | ||
473 | // across more servers. The client should consume the server list in order | ||
474 | // unless instructed otherwise via the client_config. | ||
475 | Servers []*Server `protobuf:"bytes,1,rep,name=servers" json:"servers,omitempty"` | ||
476 | // Indicates the amount of time that the client should consider this server | ||
477 | // list as valid. It may be considered stale after waiting this interval of | ||
478 | // time after receiving the list. If the interval is not positive, the | ||
479 | // client can assume the list is valid until the next list is received. | ||
480 | ExpirationInterval *Duration `protobuf:"bytes,3,opt,name=expiration_interval,json=expirationInterval" json:"expiration_interval,omitempty"` | ||
481 | } | ||
482 | |||
483 | func (m *ServerList) Reset() { *m = ServerList{} } | ||
484 | func (m *ServerList) String() string { return proto.CompactTextString(m) } | ||
485 | func (*ServerList) ProtoMessage() {} | ||
486 | func (*ServerList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } | ||
487 | |||
488 | func (m *ServerList) GetServers() []*Server { | ||
489 | if m != nil { | ||
490 | return m.Servers | ||
491 | } | ||
492 | return nil | ||
493 | } | ||
494 | |||
495 | func (m *ServerList) GetExpirationInterval() *Duration { | ||
496 | if m != nil { | ||
497 | return m.ExpirationInterval | ||
498 | } | ||
499 | return nil | ||
500 | } | ||
501 | |||
502 | // Contains server information. When none of the [drop_for_*] fields are true, | ||
503 | // use the other fields. When drop_for_rate_limiting is true, ignore all other | ||
504 | // fields. Use drop_for_load_balancing only when it is true and | ||
505 | // drop_for_rate_limiting is false. | ||
506 | type Server struct { | ||
507 | // A resolved address for the server, serialized in network-byte-order. It may | ||
508 | // either be an IPv4 or IPv6 address. | ||
509 | IpAddress []byte `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` | ||
510 | // A resolved port number for the server. | ||
511 | Port int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"` | ||
512 | // An opaque but printable token given to the frontend for each pick. All | ||
513 | // frontend requests for that pick must include the token in its initial | ||
514 | // metadata. The token is used by the backend to verify the request and to | ||
515 | // allow the backend to report load to the gRPC LB system. | ||
516 | // | ||
517 | // Its length is variable but less than 50 bytes. | ||
518 | LoadBalanceToken string `protobuf:"bytes,3,opt,name=load_balance_token,json=loadBalanceToken" json:"load_balance_token,omitempty"` | ||
519 | // Indicates whether this particular request should be dropped by the client | ||
520 | // for rate limiting. | ||
521 | DropForRateLimiting bool `protobuf:"varint,4,opt,name=drop_for_rate_limiting,json=dropForRateLimiting" json:"drop_for_rate_limiting,omitempty"` | ||
522 | // Indicates whether this particular request should be dropped by the client | ||
523 | // for load balancing. | ||
524 | DropForLoadBalancing bool `protobuf:"varint,5,opt,name=drop_for_load_balancing,json=dropForLoadBalancing" json:"drop_for_load_balancing,omitempty"` | ||
525 | } | ||
526 | |||
527 | func (m *Server) Reset() { *m = Server{} } | ||
528 | func (m *Server) String() string { return proto.CompactTextString(m) } | ||
529 | func (*Server) ProtoMessage() {} | ||
530 | func (*Server) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } | ||
531 | |||
532 | func (m *Server) GetIpAddress() []byte { | ||
533 | if m != nil { | ||
534 | return m.IpAddress | ||
535 | } | ||
536 | return nil | ||
537 | } | ||
538 | |||
539 | func (m *Server) GetPort() int32 { | ||
540 | if m != nil { | ||
541 | return m.Port | ||
542 | } | ||
543 | return 0 | ||
544 | } | ||
545 | |||
546 | func (m *Server) GetLoadBalanceToken() string { | ||
547 | if m != nil { | ||
548 | return m.LoadBalanceToken | ||
549 | } | ||
550 | return "" | ||
551 | } | ||
552 | |||
553 | func (m *Server) GetDropForRateLimiting() bool { | ||
554 | if m != nil { | ||
555 | return m.DropForRateLimiting | ||
556 | } | ||
557 | return false | ||
558 | } | ||
559 | |||
560 | func (m *Server) GetDropForLoadBalancing() bool { | ||
561 | if m != nil { | ||
562 | return m.DropForLoadBalancing | ||
563 | } | ||
564 | return false | ||
565 | } | ||
566 | |||
567 | func init() { | ||
568 | proto.RegisterType((*Duration)(nil), "grpc.lb.v1.Duration") | ||
569 | proto.RegisterType((*Timestamp)(nil), "grpc.lb.v1.Timestamp") | ||
570 | proto.RegisterType((*LoadBalanceRequest)(nil), "grpc.lb.v1.LoadBalanceRequest") | ||
571 | proto.RegisterType((*InitialLoadBalanceRequest)(nil), "grpc.lb.v1.InitialLoadBalanceRequest") | ||
572 | proto.RegisterType((*ClientStats)(nil), "grpc.lb.v1.ClientStats") | ||
573 | proto.RegisterType((*LoadBalanceResponse)(nil), "grpc.lb.v1.LoadBalanceResponse") | ||
574 | proto.RegisterType((*InitialLoadBalanceResponse)(nil), "grpc.lb.v1.InitialLoadBalanceResponse") | ||
575 | proto.RegisterType((*ServerList)(nil), "grpc.lb.v1.ServerList") | ||
576 | proto.RegisterType((*Server)(nil), "grpc.lb.v1.Server") | ||
577 | } | ||
578 | |||
579 | func init() { proto.RegisterFile("grpclb.proto", fileDescriptor0) } | ||
580 | |||
581 | var fileDescriptor0 = []byte{ | ||
582 | // 733 bytes of a gzipped FileDescriptorProto | ||
583 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x4e, 0x1b, 0x39, | ||
584 | 0x14, 0x66, 0x36, 0xfc, 0xe5, 0x24, 0x5a, 0x58, 0x93, 0x85, 0xc0, 0xc2, 0x2e, 0x1b, 0xa9, 0x34, | ||
585 | 0xaa, 0x68, 0x68, 0x43, 0x7b, 0xd1, 0x9f, 0x9b, 0x02, 0x45, 0x41, 0xe5, 0xa2, 0x72, 0xa8, 0x7a, | ||
586 | 0x55, 0x59, 0x4e, 0xc6, 0x80, 0xc5, 0xc4, 0x9e, 0xda, 0x4e, 0x68, 0x2f, 0x7b, 0xd9, 0x47, 0xe9, | ||
587 | 0x63, 0x54, 0x7d, 0x86, 0xbe, 0x4f, 0x65, 0x7b, 0x26, 0x33, 0x90, 0x1f, 0xd4, 0xbb, 0xf1, 0xf1, | ||
588 | 0x77, 0xbe, 0xf3, 0xf9, 0xd8, 0xdf, 0x19, 0x28, 0x5f, 0xa8, 0xb8, 0x1b, 0x75, 0x1a, 0xb1, 0x92, | ||
589 | 0x46, 0x22, 0xb0, 0xab, 0x46, 0xd4, 0x69, 0x0c, 0x1e, 0xd7, 0x9e, 0xc3, 0xe2, 0x51, 0x5f, 0x51, | ||
590 | 0xc3, 0xa5, 0x40, 0x55, 0x58, 0xd0, 0xac, 0x2b, 0x45, 0xa8, 0xab, 0xc1, 0x76, 0x50, 0x2f, 0xe0, | ||
591 | 0x74, 0x89, 0x2a, 0x30, 0x27, 0xa8, 0x90, 0xba, 0xfa, 0xc7, 0x76, 0x50, 0x9f, 0xc3, 0x7e, 0x51, | ||
592 | 0x7b, 0x01, 0xc5, 0x33, 0xde, 0x63, 0xda, 0xd0, 0x5e, 0xfc, 0xdb, 0xc9, 0xdf, 0x03, 0x40, 0xa7, | ||
593 | 0x92, 0x86, 0x07, 0x34, 0xa2, 0xa2, 0xcb, 0x30, 0xfb, 0xd8, 0x67, 0xda, 0xa0, 0xb7, 0xb0, 0xc4, | ||
594 | 0x05, 0x37, 0x9c, 0x46, 0x44, 0xf9, 0x90, 0xa3, 0x2b, 0x35, 0xef, 0x35, 0x32, 0xd5, 0x8d, 0x13, | ||
595 | 0x0f, 0x19, 0xcd, 0x6f, 0xcd, 0xe0, 0x3f, 0x93, 0xfc, 0x94, 0xf1, 0x25, 0x94, 0xbb, 0x11, 0x67, | ||
596 | 0xc2, 0x10, 0x6d, 0xa8, 0xf1, 0x2a, 0x4a, 0xcd, 0xb5, 0x3c, 0xdd, 0xa1, 0xdb, 0x6f, 0xdb, 0xed, | ||
597 | 0xd6, 0x0c, 0x2e, 0x75, 0xb3, 0xe5, 0xc1, 0x3f, 0xb0, 0x1e, 0x49, 0x1a, 0x92, 0x8e, 0x2f, 0x93, | ||
598 | 0x8a, 0x22, 0xe6, 0x73, 0xcc, 0x6a, 0x7b, 0xb0, 0x3e, 0x51, 0x09, 0x42, 0x30, 0x2b, 0x68, 0x8f, | ||
599 | 0x39, 0xf9, 0x45, 0xec, 0xbe, 0x6b, 0x5f, 0x67, 0xa1, 0x94, 0x2b, 0x86, 0xf6, 0xa1, 0x68, 0xd2, | ||
600 | 0x0e, 0x26, 0xe7, 0xfc, 0x3b, 0x2f, 0x6c, 0xd8, 0x5e, 0x9c, 0xe1, 0xd0, 0x03, 0xf8, 0x4b, 0xf4, | ||
601 | 0x7b, 0xa4, 0x4b, 0xa3, 0x48, 0xdb, 0x33, 0x29, 0xc3, 0x42, 0x77, 0xaa, 0x02, 0x5e, 0x12, 0xfd, | ||
602 | 0xde, 0xa1, 0x8d, 0xb7, 0x7d, 0x18, 0xed, 0x02, 0xca, 0xb0, 0xe7, 0x5c, 0x70, 0x7d, 0xc9, 0xc2, | ||
603 | 0x6a, 0xc1, 0x81, 0x97, 0x53, 0xf0, 0x71, 0x12, 0x47, 0x04, 0x1a, 0xa3, 0x68, 0x72, 0xcd, 0xcd, | ||
604 | 0x25, 0x09, 0x95, 0x8c, 0xc9, 0xb9, 0x54, 0x44, 0x51, 0xc3, 0x48, 0xc4, 0x7b, 0xdc, 0x70, 0x71, | ||
605 | 0x51, 0x9d, 0x75, 0x4c, 0xf7, 0x6f, 0x33, 0xbd, 0xe7, 0xe6, 0xf2, 0x48, 0xc9, 0xf8, 0x58, 0x2a, | ||
606 | 0x4c, 0x0d, 0x3b, 0x4d, 0xe0, 0x88, 0xc2, 0xde, 0x9d, 0x05, 0x72, 0xed, 0xb6, 0x15, 0xe6, 0x5c, | ||
607 | 0x85, 0xfa, 0x94, 0x0a, 0x59, 0xef, 0x6d, 0x89, 0x0f, 0xf0, 0x70, 0x52, 0x89, 0xe4, 0x19, 0x9c, | ||
608 | 0x53, 0x1e, 0xb1, 0x90, 0x18, 0x49, 0x34, 0x13, 0x61, 0x75, 0xde, 0x15, 0xd8, 0x19, 0x57, 0xc0, | ||
609 | 0x5f, 0xd5, 0xb1, 0xc3, 0x9f, 0xc9, 0x36, 0x13, 0x21, 0x6a, 0xc1, 0xff, 0x63, 0xe8, 0xaf, 0x84, | ||
610 | 0xbc, 0x16, 0x44, 0xb1, 0x2e, 0xe3, 0x03, 0x16, 0x56, 0x17, 0x1c, 0xe5, 0xd6, 0x6d, 0xca, 0x37, | ||
611 | 0x16, 0x85, 0x13, 0x50, 0xed, 0x47, 0x00, 0x2b, 0x37, 0x9e, 0x8d, 0x8e, 0xa5, 0xd0, 0x0c, 0xb5, | ||
612 | 0x61, 0x39, 0x73, 0x80, 0x8f, 0x25, 0x4f, 0x63, 0xe7, 0x2e, 0x0b, 0x78, 0x74, 0x6b, 0x06, 0x2f, | ||
613 | 0x0d, 0x3d, 0x90, 0x90, 0x3e, 0x83, 0x92, 0x66, 0x6a, 0xc0, 0x14, 0x89, 0xb8, 0x36, 0x89, 0x07, | ||
614 | 0x56, 0xf3, 0x7c, 0x6d, 0xb7, 0x7d, 0xca, 0x9d, 0x87, 0x40, 0x0f, 0x57, 0x07, 0x9b, 0xb0, 0x71, | ||
615 | 0xcb, 0x01, 0x9e, 0xd3, 0x5b, 0xe0, 0x5b, 0x00, 0x1b, 0x93, 0xa5, 0xa0, 0x27, 0xb0, 0x9a, 0x4f, | ||
616 | 0x56, 0x24, 0x64, 0x11, 0xbb, 0xa0, 0x26, 0xb5, 0x45, 0x25, 0xca, 0x92, 0xd4, 0x51, 0xb2, 0x87, | ||
617 | 0xde, 0xc1, 0x66, 0xde, 0xb2, 0x44, 0xb1, 0x58, 0x2a, 0x43, 0xb8, 0x30, 0x4c, 0x0d, 0x68, 0x94, | ||
618 | 0xc8, 0xaf, 0xe4, 0xe5, 0xa7, 0x43, 0x0c, 0xaf, 0xe7, 0xdc, 0x8b, 0x5d, 0xde, 0x49, 0x92, 0x56, | ||
619 | 0xfb, 0x12, 0x00, 0x64, 0xc7, 0x44, 0xbb, 0x76, 0x62, 0xd9, 0x95, 0x9d, 0x58, 0x85, 0x7a, 0xa9, | ||
620 | 0x89, 0x46, 0xfb, 0x81, 0x53, 0x08, 0x7a, 0x0d, 0x2b, 0xec, 0x53, 0xcc, 0x7d, 0x95, 0x4c, 0x4a, | ||
621 | 0x61, 0x8a, 0x14, 0x94, 0x25, 0x0c, 0x35, 0xfc, 0x0c, 0x60, 0xde, 0x53, 0xa3, 0x2d, 0x00, 0x1e, | ||
622 | 0x13, 0x1a, 0x86, 0x8a, 0x69, 0x3f, 0x34, 0xcb, 0xb8, 0xc8, 0xe3, 0x57, 0x3e, 0x60, 0xe7, 0x87, | ||
623 | 0x55, 0x9f, 0x4c, 0x4d, 0xf7, 0x6d, 0xed, 0x7c, 0xe3, 0x2e, 0x8c, 0xbc, 0x62, 0xc2, 0x69, 0x28, | ||
624 | 0xe2, 0xe5, 0x5c, 0x2b, 0xcf, 0x6c, 0x1c, 0xed, 0xc3, 0xea, 0x14, 0xdb, 0x2e, 0xe2, 0x95, 0x70, | ||
625 | 0x8c, 0x45, 0x9f, 0xc2, 0xda, 0x34, 0x2b, 0x2e, 0xe2, 0x4a, 0x38, 0xc6, 0x76, 0xcd, 0x0e, 0x94, | ||
626 | 0x73, 0xf7, 0xaf, 0x10, 0x86, 0x52, 0xf2, 0x6d, 0xc3, 0xe8, 0xdf, 0x7c, 0x83, 0x46, 0x87, 0xe5, | ||
627 | 0xc6, 0x7f, 0x13, 0xf7, 0xfd, 0x43, 0xaa, 0x07, 0x8f, 0x82, 0xce, 0xbc, 0xfb, 0x7d, 0xed, 0xff, | ||
628 | 0x0a, 0x00, 0x00, 0xff, 0xff, 0x64, 0xbf, 0xda, 0x5e, 0xce, 0x06, 0x00, 0x00, | ||
629 | } | ||
diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.proto b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.proto deleted file mode 100644 index b13b343..0000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/grpclb.proto +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | // Copyright 2016 gRPC authors. | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | syntax = "proto3"; | ||
16 | |||
17 | package grpc.lb.v1; | ||
18 | |||
19 | message Duration { | ||
20 | // Signed seconds of the span of time. Must be from -315,576,000,000 | ||
21 | // to +315,576,000,000 inclusive. | ||
22 | int64 seconds = 1; | ||
23 | |||
24 | // Signed fractions of a second at nanosecond resolution of the span | ||
25 | // of time. Durations less than one second are represented with a 0 | ||
26 | // `seconds` field and a positive or negative `nanos` field. For durations | ||
27 | // of one second or more, a non-zero value for the `nanos` field must be | ||
28 | // of the same sign as the `seconds` field. Must be from -999,999,999 | ||
29 | // to +999,999,999 inclusive. | ||
30 | int32 nanos = 2; | ||
31 | } | ||
32 | |||
33 | message Timestamp { | ||
34 | |||
35 | // Represents seconds of UTC time since Unix epoch | ||
36 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to | ||
37 | // 9999-12-31T23:59:59Z inclusive. | ||
38 | int64 seconds = 1; | ||
39 | |||
40 | // Non-negative fractions of a second at nanosecond resolution. Negative | ||
41 | // second values with fractions must still have non-negative nanos values | ||
42 | // that count forward in time. Must be from 0 to 999,999,999 | ||
43 | // inclusive. | ||
44 | int32 nanos = 2; | ||
45 | } | ||
46 | |||
47 | service LoadBalancer { | ||
48 | // Bidirectional rpc to get a list of servers. | ||
49 | rpc BalanceLoad(stream LoadBalanceRequest) | ||
50 | returns (stream LoadBalanceResponse); | ||
51 | } | ||
52 | |||
53 | message LoadBalanceRequest { | ||
54 | oneof load_balance_request_type { | ||
55 | // This message should be sent on the first request to the load balancer. | ||
56 | InitialLoadBalanceRequest initial_request = 1; | ||
57 | |||
58 | // The client stats should be periodically reported to the load balancer | ||
59 | // based on the duration defined in the InitialLoadBalanceResponse. | ||
60 | ClientStats client_stats = 2; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | message InitialLoadBalanceRequest { | ||
65 | // Name of load balanced service (IE, balancer.service.com) | ||
66 | // length should be less than 256 bytes. | ||
67 | string name = 1; | ||
68 | } | ||
69 | |||
70 | // Contains client level statistics that are useful to load balancing. Each | ||
71 | // count except the timestamp should be reset to zero after reporting the stats. | ||
72 | message ClientStats { | ||
73 | // The timestamp of generating the report. | ||
74 | Timestamp timestamp = 1; | ||
75 | |||
76 | // The total number of RPCs that started. | ||
77 | int64 num_calls_started = 2; | ||
78 | |||
79 | // The total number of RPCs that finished. | ||
80 | int64 num_calls_finished = 3; | ||
81 | |||
82 | // The total number of RPCs that were dropped by the client because of rate | ||
83 | // limiting. | ||
84 | int64 num_calls_finished_with_drop_for_rate_limiting = 4; | ||
85 | |||
86 | // The total number of RPCs that were dropped by the client because of load | ||
87 | // balancing. | ||
88 | int64 num_calls_finished_with_drop_for_load_balancing = 5; | ||
89 | |||
90 | // The total number of RPCs that failed to reach a server except dropped RPCs. | ||
91 | int64 num_calls_finished_with_client_failed_to_send = 6; | ||
92 | |||
93 | // The total number of RPCs that finished and are known to have been received | ||
94 | // by a server. | ||
95 | int64 num_calls_finished_known_received = 7; | ||
96 | } | ||
97 | |||
98 | message LoadBalanceResponse { | ||
99 | oneof load_balance_response_type { | ||
100 | // This message should be sent on the first response to the client. | ||
101 | InitialLoadBalanceResponse initial_response = 1; | ||
102 | |||
103 | // Contains the list of servers selected by the load balancer. The client | ||
104 | // should send requests to these servers in the specified order. | ||
105 | ServerList server_list = 2; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | message InitialLoadBalanceResponse { | ||
110 | // This is an application layer redirect that indicates the client should use | ||
111 | // the specified server for load balancing. When this field is non-empty in | ||
112 | // the response, the client should open a separate connection to the | ||
113 | // load_balancer_delegate and call the BalanceLoad method. Its length should | ||
114 | // be less than 64 bytes. | ||
115 | string load_balancer_delegate = 1; | ||
116 | |||
117 | // This interval defines how often the client should send the client stats | ||
118 | // to the load balancer. Stats should only be reported when the duration is | ||
119 | // positive. | ||
120 | Duration client_stats_report_interval = 2; | ||
121 | } | ||
122 | |||
123 | message ServerList { | ||
124 | // Contains a list of servers selected by the load balancer. The list will | ||
125 | // be updated when server resolutions change or as needed to balance load | ||
126 | // across more servers. The client should consume the server list in order | ||
127 | // unless instructed otherwise via the client_config. | ||
128 | repeated Server servers = 1; | ||
129 | |||
130 | // Indicates the amount of time that the client should consider this server | ||
131 | // list as valid. It may be considered stale after waiting this interval of | ||
132 | // time after receiving the list. If the interval is not positive, the | ||
133 | // client can assume the list is valid until the next list is received. | ||
134 | Duration expiration_interval = 3; | ||
135 | } | ||
136 | |||
137 | // Contains server information. When none of the [drop_for_*] fields are true, | ||
138 | // use the other fields. When drop_for_rate_limiting is true, ignore all other | ||
139 | // fields. Use drop_for_load_balancing only when it is true and | ||
140 | // drop_for_rate_limiting is false. | ||
141 | message Server { | ||
142 | // A resolved address for the server, serialized in network-byte-order. It may | ||
143 | // either be an IPv4 or IPv6 address. | ||
144 | bytes ip_address = 1; | ||
145 | |||
146 | // A resolved port number for the server. | ||
147 | int32 port = 2; | ||
148 | |||
149 | // An opaque but printable token given to the frontend for each pick. All | ||
150 | // frontend requests for that pick must include the token in its initial | ||
151 | // metadata. The token is used by the backend to verify the request and to | ||
152 | // allow the backend to report load to the gRPC LB system. | ||
153 | // | ||
154 | // Its length is variable but less than 50 bytes. | ||
155 | string load_balance_token = 3; | ||
156 | |||
157 | // Indicates whether this particular request should be dropped by the client | ||
158 | // for rate limiting. | ||
159 | bool drop_for_rate_limiting = 4; | ||
160 | |||
161 | // Indicates whether this particular request should be dropped by the client | ||
162 | // for load balancing. | ||
163 | bool drop_for_load_balancing = 5; | ||
164 | } | ||
diff --git a/vendor/google.golang.org/grpc/grpclog/grpclog.go b/vendor/google.golang.org/grpc/grpclog/grpclog.go index 16a7d88..1fabb11 100644 --- a/vendor/google.golang.org/grpc/grpclog/grpclog.go +++ b/vendor/google.golang.org/grpc/grpclog/grpclog.go | |||
@@ -105,18 +105,21 @@ func Fatalln(args ...interface{}) { | |||
105 | } | 105 | } |
106 | 106 | ||
107 | // Print prints to the logger. Arguments are handled in the manner of fmt.Print. | 107 | // Print prints to the logger. Arguments are handled in the manner of fmt.Print. |
108 | // | ||
108 | // Deprecated: use Info. | 109 | // Deprecated: use Info. |
109 | func Print(args ...interface{}) { | 110 | func Print(args ...interface{}) { |
110 | logger.Info(args...) | 111 | logger.Info(args...) |
111 | } | 112 | } |
112 | 113 | ||
113 | // Printf prints to the logger. Arguments are handled in the manner of fmt.Printf. | 114 | // Printf prints to the logger. Arguments are handled in the manner of fmt.Printf. |
115 | // | ||
114 | // Deprecated: use Infof. | 116 | // Deprecated: use Infof. |
115 | func Printf(format string, args ...interface{}) { | 117 | func Printf(format string, args ...interface{}) { |
116 | logger.Infof(format, args...) | 118 | logger.Infof(format, args...) |
117 | } | 119 | } |
118 | 120 | ||
119 | // Println prints to the logger. Arguments are handled in the manner of fmt.Println. | 121 | // Println prints to the logger. Arguments are handled in the manner of fmt.Println. |
122 | // | ||
120 | // Deprecated: use Infoln. | 123 | // Deprecated: use Infoln. |
121 | func Println(args ...interface{}) { | 124 | func Println(args ...interface{}) { |
122 | logger.Infoln(args...) | 125 | logger.Infoln(args...) |
diff --git a/vendor/google.golang.org/grpc/grpclog/logger.go b/vendor/google.golang.org/grpc/grpclog/logger.go index d03b239..097494f 100644 --- a/vendor/google.golang.org/grpc/grpclog/logger.go +++ b/vendor/google.golang.org/grpc/grpclog/logger.go | |||
@@ -19,6 +19,7 @@ | |||
19 | package grpclog | 19 | package grpclog |
20 | 20 | ||
21 | // Logger mimics golang's standard Logger as an interface. | 21 | // Logger mimics golang's standard Logger as an interface. |
22 | // | ||
22 | // Deprecated: use LoggerV2. | 23 | // Deprecated: use LoggerV2. |
23 | type Logger interface { | 24 | type Logger interface { |
24 | Fatal(args ...interface{}) | 25 | Fatal(args ...interface{}) |
@@ -31,6 +32,7 @@ type Logger interface { | |||
31 | 32 | ||
32 | // SetLogger sets the logger that is used in grpc. Call only from | 33 | // SetLogger sets the logger that is used in grpc. Call only from |
33 | // init() functions. | 34 | // init() functions. |
35 | // | ||
34 | // Deprecated: use SetLoggerV2. | 36 | // Deprecated: use SetLoggerV2. |
35 | func SetLogger(l Logger) { | 37 | func SetLogger(l Logger) { |
36 | logger = &loggerWrapper{Logger: l} | 38 | logger = &loggerWrapper{Logger: l} |
diff --git a/vendor/google.golang.org/grpc/health/client.go b/vendor/google.golang.org/grpc/health/client.go new file mode 100644 index 0000000..e15f04c --- /dev/null +++ b/vendor/google.golang.org/grpc/health/client.go | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package health | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | "fmt" | ||
24 | "io" | ||
25 | "time" | ||
26 | |||
27 | "google.golang.org/grpc" | ||
28 | "google.golang.org/grpc/codes" | ||
29 | healthpb "google.golang.org/grpc/health/grpc_health_v1" | ||
30 | "google.golang.org/grpc/internal" | ||
31 | "google.golang.org/grpc/internal/backoff" | ||
32 | "google.golang.org/grpc/status" | ||
33 | ) | ||
34 | |||
35 | const maxDelay = 120 * time.Second | ||
36 | |||
37 | var backoffStrategy = backoff.Exponential{MaxDelay: maxDelay} | ||
38 | var backoffFunc = func(ctx context.Context, retries int) bool { | ||
39 | d := backoffStrategy.Backoff(retries) | ||
40 | timer := time.NewTimer(d) | ||
41 | select { | ||
42 | case <-timer.C: | ||
43 | return true | ||
44 | case <-ctx.Done(): | ||
45 | timer.Stop() | ||
46 | return false | ||
47 | } | ||
48 | } | ||
49 | |||
50 | func init() { | ||
51 | internal.HealthCheckFunc = clientHealthCheck | ||
52 | } | ||
53 | |||
54 | func clientHealthCheck(ctx context.Context, newStream func() (interface{}, error), reportHealth func(bool), service string) error { | ||
55 | tryCnt := 0 | ||
56 | |||
57 | retryConnection: | ||
58 | for { | ||
59 | // Backs off if the connection has failed in some way without receiving a message in the previous retry. | ||
60 | if tryCnt > 0 && !backoffFunc(ctx, tryCnt-1) { | ||
61 | return nil | ||
62 | } | ||
63 | tryCnt++ | ||
64 | |||
65 | if ctx.Err() != nil { | ||
66 | return nil | ||
67 | } | ||
68 | rawS, err := newStream() | ||
69 | if err != nil { | ||
70 | continue retryConnection | ||
71 | } | ||
72 | |||
73 | s, ok := rawS.(grpc.ClientStream) | ||
74 | // Ideally, this should never happen. But if it happens, the server is marked as healthy for LBing purposes. | ||
75 | if !ok { | ||
76 | reportHealth(true) | ||
77 | return fmt.Errorf("newStream returned %v (type %T); want grpc.ClientStream", rawS, rawS) | ||
78 | } | ||
79 | |||
80 | if err = s.SendMsg(&healthpb.HealthCheckRequest{Service: service}); err != nil && err != io.EOF { | ||
81 | // Stream should have been closed, so we can safely continue to create a new stream. | ||
82 | continue retryConnection | ||
83 | } | ||
84 | s.CloseSend() | ||
85 | |||
86 | resp := new(healthpb.HealthCheckResponse) | ||
87 | for { | ||
88 | err = s.RecvMsg(resp) | ||
89 | |||
90 | // Reports healthy for the LBing purposes if health check is not implemented in the server. | ||
91 | if status.Code(err) == codes.Unimplemented { | ||
92 | reportHealth(true) | ||
93 | return err | ||
94 | } | ||
95 | |||
96 | // Reports unhealthy if server's Watch method gives an error other than UNIMPLEMENTED. | ||
97 | if err != nil { | ||
98 | reportHealth(false) | ||
99 | continue retryConnection | ||
100 | } | ||
101 | |||
102 | // As a message has been received, removes the need for backoff for the next retry by reseting the try count. | ||
103 | tryCnt = 0 | ||
104 | reportHealth(resp.Status == healthpb.HealthCheckResponse_SERVING) | ||
105 | } | ||
106 | } | ||
107 | } | ||
diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go index 89c4d45..c2f2c77 100644 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go +++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go | |||
@@ -1,18 +1,7 @@ | |||
1 | // Code generated by protoc-gen-go. | 1 | // Code generated by protoc-gen-go. DO NOT EDIT. |
2 | // source: health.proto | 2 | // source: grpc/health/v1/health.proto |
3 | // DO NOT EDIT! | ||
4 | 3 | ||
5 | /* | 4 | package grpc_health_v1 // import "google.golang.org/grpc/health/grpc_health_v1" |
6 | Package grpc_health_v1 is a generated protocol buffer package. | ||
7 | |||
8 | It is generated from these files: | ||
9 | health.proto | ||
10 | |||
11 | It has these top-level messages: | ||
12 | HealthCheckRequest | ||
13 | HealthCheckResponse | ||
14 | */ | ||
15 | package grpc_health_v1 | ||
16 | 5 | ||
17 | import proto "github.com/golang/protobuf/proto" | 6 | import proto "github.com/golang/protobuf/proto" |
18 | import fmt "fmt" | 7 | import fmt "fmt" |
@@ -37,46 +26,107 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | |||
37 | type HealthCheckResponse_ServingStatus int32 | 26 | type HealthCheckResponse_ServingStatus int32 |
38 | 27 | ||
39 | const ( | 28 | const ( |
40 | HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 | 29 | HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 |
41 | HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 | 30 | HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 |
42 | HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 | 31 | HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 |
32 | HealthCheckResponse_SERVICE_UNKNOWN HealthCheckResponse_ServingStatus = 3 | ||
43 | ) | 33 | ) |
44 | 34 | ||
45 | var HealthCheckResponse_ServingStatus_name = map[int32]string{ | 35 | var HealthCheckResponse_ServingStatus_name = map[int32]string{ |
46 | 0: "UNKNOWN", | 36 | 0: "UNKNOWN", |
47 | 1: "SERVING", | 37 | 1: "SERVING", |
48 | 2: "NOT_SERVING", | 38 | 2: "NOT_SERVING", |
39 | 3: "SERVICE_UNKNOWN", | ||
49 | } | 40 | } |
50 | var HealthCheckResponse_ServingStatus_value = map[string]int32{ | 41 | var HealthCheckResponse_ServingStatus_value = map[string]int32{ |
51 | "UNKNOWN": 0, | 42 | "UNKNOWN": 0, |
52 | "SERVING": 1, | 43 | "SERVING": 1, |
53 | "NOT_SERVING": 2, | 44 | "NOT_SERVING": 2, |
45 | "SERVICE_UNKNOWN": 3, | ||
54 | } | 46 | } |
55 | 47 | ||
56 | func (x HealthCheckResponse_ServingStatus) String() string { | 48 | func (x HealthCheckResponse_ServingStatus) String() string { |
57 | return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x)) | 49 | return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x)) |
58 | } | 50 | } |
59 | func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { | 51 | func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { |
60 | return fileDescriptor0, []int{1, 0} | 52 | return fileDescriptor_health_6b1a06aa67f91efd, []int{1, 0} |
61 | } | 53 | } |
62 | 54 | ||
63 | type HealthCheckRequest struct { | 55 | type HealthCheckRequest struct { |
64 | Service string `protobuf:"bytes,1,opt,name=service" json:"service,omitempty"` | 56 | Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` |
57 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
58 | XXX_unrecognized []byte `json:"-"` | ||
59 | XXX_sizecache int32 `json:"-"` | ||
60 | } | ||
61 | |||
62 | func (m *HealthCheckRequest) Reset() { *m = HealthCheckRequest{} } | ||
63 | func (m *HealthCheckRequest) String() string { return proto.CompactTextString(m) } | ||
64 | func (*HealthCheckRequest) ProtoMessage() {} | ||
65 | func (*HealthCheckRequest) Descriptor() ([]byte, []int) { | ||
66 | return fileDescriptor_health_6b1a06aa67f91efd, []int{0} | ||
67 | } | ||
68 | func (m *HealthCheckRequest) XXX_Unmarshal(b []byte) error { | ||
69 | return xxx_messageInfo_HealthCheckRequest.Unmarshal(m, b) | ||
70 | } | ||
71 | func (m *HealthCheckRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
72 | return xxx_messageInfo_HealthCheckRequest.Marshal(b, m, deterministic) | ||
73 | } | ||
74 | func (dst *HealthCheckRequest) XXX_Merge(src proto.Message) { | ||
75 | xxx_messageInfo_HealthCheckRequest.Merge(dst, src) | ||
76 | } | ||
77 | func (m *HealthCheckRequest) XXX_Size() int { | ||
78 | return xxx_messageInfo_HealthCheckRequest.Size(m) | ||
79 | } | ||
80 | func (m *HealthCheckRequest) XXX_DiscardUnknown() { | ||
81 | xxx_messageInfo_HealthCheckRequest.DiscardUnknown(m) | ||
65 | } | 82 | } |
66 | 83 | ||
67 | func (m *HealthCheckRequest) Reset() { *m = HealthCheckRequest{} } | 84 | var xxx_messageInfo_HealthCheckRequest proto.InternalMessageInfo |
68 | func (m *HealthCheckRequest) String() string { return proto.CompactTextString(m) } | 85 | |
69 | func (*HealthCheckRequest) ProtoMessage() {} | 86 | func (m *HealthCheckRequest) GetService() string { |
70 | func (*HealthCheckRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } | 87 | if m != nil { |
88 | return m.Service | ||
89 | } | ||
90 | return "" | ||
91 | } | ||
71 | 92 | ||
72 | type HealthCheckResponse struct { | 93 | type HealthCheckResponse struct { |
73 | Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,enum=grpc.health.v1.HealthCheckResponse_ServingStatus" json:"status,omitempty"` | 94 | Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=grpc.health.v1.HealthCheckResponse_ServingStatus" json:"status,omitempty"` |
95 | XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||
96 | XXX_unrecognized []byte `json:"-"` | ||
97 | XXX_sizecache int32 `json:"-"` | ||
74 | } | 98 | } |
75 | 99 | ||
76 | func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} } | 100 | func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} } |
77 | func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) } | 101 | func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) } |
78 | func (*HealthCheckResponse) ProtoMessage() {} | 102 | func (*HealthCheckResponse) ProtoMessage() {} |
79 | func (*HealthCheckResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } | 103 | func (*HealthCheckResponse) Descriptor() ([]byte, []int) { |
104 | return fileDescriptor_health_6b1a06aa67f91efd, []int{1} | ||
105 | } | ||
106 | func (m *HealthCheckResponse) XXX_Unmarshal(b []byte) error { | ||
107 | return xxx_messageInfo_HealthCheckResponse.Unmarshal(m, b) | ||
108 | } | ||
109 | func (m *HealthCheckResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||
110 | return xxx_messageInfo_HealthCheckResponse.Marshal(b, m, deterministic) | ||
111 | } | ||
112 | func (dst *HealthCheckResponse) XXX_Merge(src proto.Message) { | ||
113 | xxx_messageInfo_HealthCheckResponse.Merge(dst, src) | ||
114 | } | ||
115 | func (m *HealthCheckResponse) XXX_Size() int { | ||
116 | return xxx_messageInfo_HealthCheckResponse.Size(m) | ||
117 | } | ||
118 | func (m *HealthCheckResponse) XXX_DiscardUnknown() { | ||
119 | xxx_messageInfo_HealthCheckResponse.DiscardUnknown(m) | ||
120 | } | ||
121 | |||
122 | var xxx_messageInfo_HealthCheckResponse proto.InternalMessageInfo | ||
123 | |||
124 | func (m *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { | ||
125 | if m != nil { | ||
126 | return m.Status | ||
127 | } | ||
128 | return HealthCheckResponse_UNKNOWN | ||
129 | } | ||
80 | 130 | ||
81 | func init() { | 131 | func init() { |
82 | proto.RegisterType((*HealthCheckRequest)(nil), "grpc.health.v1.HealthCheckRequest") | 132 | proto.RegisterType((*HealthCheckRequest)(nil), "grpc.health.v1.HealthCheckRequest") |
@@ -92,10 +142,29 @@ var _ grpc.ClientConn | |||
92 | // is compatible with the grpc package it is being compiled against. | 142 | // is compatible with the grpc package it is being compiled against. |
93 | const _ = grpc.SupportPackageIsVersion4 | 143 | const _ = grpc.SupportPackageIsVersion4 |
94 | 144 | ||
95 | // Client API for Health service | 145 | // HealthClient is the client API for Health service. |
96 | 146 | // | |
147 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. | ||
97 | type HealthClient interface { | 148 | type HealthClient interface { |
149 | // If the requested service is unknown, the call will fail with status | ||
150 | // NOT_FOUND. | ||
98 | Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) | 151 | Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) |
152 | // Performs a watch for the serving status of the requested service. | ||
153 | // The server will immediately send back a message indicating the current | ||
154 | // serving status. It will then subsequently send a new message whenever | ||
155 | // the service's serving status changes. | ||
156 | // | ||
157 | // If the requested service is unknown when the call is received, the | ||
158 | // server will send a message setting the serving status to | ||
159 | // SERVICE_UNKNOWN but will *not* terminate the call. If at some | ||
160 | // future point, the serving status of the service becomes known, the | ||
161 | // server will send a new message with the service's serving status. | ||
162 | // | ||
163 | // If the call terminates with status UNIMPLEMENTED, then clients | ||
164 | // should assume this method is not supported and should not retry the | ||
165 | // call. If the call terminates with any other status (including OK), | ||
166 | // clients should retry the call with appropriate exponential backoff. | ||
167 | Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error) | ||
99 | } | 168 | } |
100 | 169 | ||
101 | type healthClient struct { | 170 | type healthClient struct { |
@@ -108,17 +177,66 @@ func NewHealthClient(cc *grpc.ClientConn) HealthClient { | |||
108 | 177 | ||
109 | func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) { | 178 | func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) { |
110 | out := new(HealthCheckResponse) | 179 | out := new(HealthCheckResponse) |
111 | err := grpc.Invoke(ctx, "/grpc.health.v1.Health/Check", in, out, c.cc, opts...) | 180 | err := c.cc.Invoke(ctx, "/grpc.health.v1.Health/Check", in, out, opts...) |
112 | if err != nil { | 181 | if err != nil { |
113 | return nil, err | 182 | return nil, err |
114 | } | 183 | } |
115 | return out, nil | 184 | return out, nil |
116 | } | 185 | } |
117 | 186 | ||
118 | // Server API for Health service | 187 | func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error) { |
188 | stream, err := c.cc.NewStream(ctx, &_Health_serviceDesc.Streams[0], "/grpc.health.v1.Health/Watch", opts...) | ||
189 | if err != nil { | ||
190 | return nil, err | ||
191 | } | ||
192 | x := &healthWatchClient{stream} | ||
193 | if err := x.ClientStream.SendMsg(in); err != nil { | ||
194 | return nil, err | ||
195 | } | ||
196 | if err := x.ClientStream.CloseSend(); err != nil { | ||
197 | return nil, err | ||
198 | } | ||
199 | return x, nil | ||
200 | } | ||
201 | |||
202 | type Health_WatchClient interface { | ||
203 | Recv() (*HealthCheckResponse, error) | ||
204 | grpc.ClientStream | ||
205 | } | ||
206 | |||
207 | type healthWatchClient struct { | ||
208 | grpc.ClientStream | ||
209 | } | ||
119 | 210 | ||
211 | func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) { | ||
212 | m := new(HealthCheckResponse) | ||
213 | if err := x.ClientStream.RecvMsg(m); err != nil { | ||
214 | return nil, err | ||
215 | } | ||
216 | return m, nil | ||
217 | } | ||
218 | |||
219 | // HealthServer is the server API for Health service. | ||
120 | type HealthServer interface { | 220 | type HealthServer interface { |
221 | // If the requested service is unknown, the call will fail with status | ||
222 | // NOT_FOUND. | ||
121 | Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) | 223 | Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) |
224 | // Performs a watch for the serving status of the requested service. | ||
225 | // The server will immediately send back a message indicating the current | ||
226 | // serving status. It will then subsequently send a new message whenever | ||
227 | // the service's serving status changes. | ||
228 | // | ||
229 | // If the requested service is unknown when the call is received, the | ||
230 | // server will send a message setting the serving status to | ||
231 | // SERVICE_UNKNOWN but will *not* terminate the call. If at some | ||
232 | // future point, the serving status of the service becomes known, the | ||
233 | // server will send a new message with the service's serving status. | ||
234 | // | ||
235 | // If the call terminates with status UNIMPLEMENTED, then clients | ||
236 | // should assume this method is not supported and should not retry the | ||
237 | // call. If the call terminates with any other status (including OK), | ||
238 | // clients should retry the call with appropriate exponential backoff. | ||
239 | Watch(*HealthCheckRequest, Health_WatchServer) error | ||
122 | } | 240 | } |
123 | 241 | ||
124 | func RegisterHealthServer(s *grpc.Server, srv HealthServer) { | 242 | func RegisterHealthServer(s *grpc.Server, srv HealthServer) { |
@@ -143,6 +261,27 @@ func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interf | |||
143 | return interceptor(ctx, in, info, handler) | 261 | return interceptor(ctx, in, info, handler) |
144 | } | 262 | } |
145 | 263 | ||
264 | func _Health_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { | ||
265 | m := new(HealthCheckRequest) | ||
266 | if err := stream.RecvMsg(m); err != nil { | ||
267 | return err | ||
268 | } | ||
269 | return srv.(HealthServer).Watch(m, &healthWatchServer{stream}) | ||
270 | } | ||
271 | |||
272 | type Health_WatchServer interface { | ||
273 | Send(*HealthCheckResponse) error | ||
274 | grpc.ServerStream | ||
275 | } | ||
276 | |||
277 | type healthWatchServer struct { | ||
278 | grpc.ServerStream | ||
279 | } | ||
280 | |||
281 | func (x *healthWatchServer) Send(m *HealthCheckResponse) error { | ||
282 | return x.ServerStream.SendMsg(m) | ||
283 | } | ||
284 | |||
146 | var _Health_serviceDesc = grpc.ServiceDesc{ | 285 | var _Health_serviceDesc = grpc.ServiceDesc{ |
147 | ServiceName: "grpc.health.v1.Health", | 286 | ServiceName: "grpc.health.v1.Health", |
148 | HandlerType: (*HealthServer)(nil), | 287 | HandlerType: (*HealthServer)(nil), |
@@ -152,25 +291,37 @@ var _Health_serviceDesc = grpc.ServiceDesc{ | |||
152 | Handler: _Health_Check_Handler, | 291 | Handler: _Health_Check_Handler, |
153 | }, | 292 | }, |
154 | }, | 293 | }, |
155 | Streams: []grpc.StreamDesc{}, | 294 | Streams: []grpc.StreamDesc{ |
156 | Metadata: "health.proto", | 295 | { |
157 | } | 296 | StreamName: "Watch", |
158 | 297 | Handler: _Health_Watch_Handler, | |
159 | func init() { proto.RegisterFile("health.proto", fileDescriptor0) } | 298 | ServerStreams: true, |
160 | 299 | }, | |
161 | var fileDescriptor0 = []byte{ | 300 | }, |
162 | // 204 bytes of a gzipped FileDescriptorProto | 301 | Metadata: "grpc/health/v1/health.proto", |
163 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0x48, 0x4d, 0xcc, | 302 | } |
164 | 0x29, 0xc9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4b, 0x2f, 0x2a, 0x48, 0xd6, 0x83, | 303 | |
165 | 0x0a, 0x95, 0x19, 0x2a, 0xe9, 0x71, 0x09, 0x79, 0x80, 0x39, 0xce, 0x19, 0xa9, 0xc9, 0xd9, 0x41, | 304 | func init() { proto.RegisterFile("grpc/health/v1/health.proto", fileDescriptor_health_6b1a06aa67f91efd) } |
166 | 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0x45, 0x65, 0x99, 0xc9, | 305 | |
167 | 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x30, 0xae, 0xd2, 0x1c, 0x46, 0x2e, 0x61, 0x14, | 306 | var fileDescriptor_health_6b1a06aa67f91efd = []byte{ |
168 | 0x0d, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x9e, 0x5c, 0x6c, 0xc5, 0x25, 0x89, 0x25, 0xa5, | 307 | // 297 bytes of a gzipped FileDescriptorProto |
169 | 0xc5, 0x60, 0x0d, 0x7c, 0x46, 0x86, 0x7a, 0xa8, 0x16, 0xe9, 0x61, 0xd1, 0xa4, 0x17, 0x0c, 0x32, | 308 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0x2f, 0x2a, 0x48, |
170 | 0x34, 0x2f, 0x3d, 0x18, 0xac, 0x31, 0x08, 0x6a, 0x80, 0x92, 0x15, 0x17, 0x2f, 0x8a, 0x84, 0x10, | 309 | 0xd6, 0xcf, 0x48, 0x4d, 0xcc, 0x29, 0xc9, 0xd0, 0x2f, 0x33, 0x84, 0xb2, 0xf4, 0x0a, 0x8a, 0xf2, |
171 | 0x37, 0x17, 0x7b, 0xa8, 0x9f, 0xb7, 0x9f, 0x7f, 0xb8, 0x9f, 0x00, 0x03, 0x88, 0x13, 0xec, 0x1a, | 310 | 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0x25, 0x3d, 0x2e, 0x21, 0x0f, |
172 | 0x14, 0xe6, 0xe9, 0xe7, 0x2e, 0xc0, 0x28, 0xc4, 0xcf, 0xc5, 0xed, 0xe7, 0x1f, 0x12, 0x0f, 0x13, | 311 | 0x30, 0xc7, 0x39, 0x23, 0x35, 0x39, 0x3b, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44, 0x48, 0x82, |
173 | 0x60, 0x32, 0x8a, 0xe2, 0x62, 0x83, 0x58, 0x24, 0x14, 0xc0, 0xc5, 0x0a, 0xb6, 0x4c, 0x48, 0x09, | 312 | 0x8b, 0xbd, 0x38, 0xb5, 0xa8, 0x2c, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, |
174 | 0xaf, 0x4b, 0xc0, 0xfe, 0x95, 0x52, 0x26, 0xc2, 0xb5, 0x49, 0x6c, 0xe0, 0x10, 0x34, 0x06, 0x04, | 313 | 0xc6, 0x55, 0xda, 0xc8, 0xc8, 0x25, 0x8c, 0xa2, 0xa1, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, |
175 | 0x00, 0x00, 0xff, 0xff, 0xac, 0x56, 0x2a, 0xcb, 0x51, 0x01, 0x00, 0x00, | 314 | 0x93, 0x8b, 0xad, 0xb8, 0x24, 0xb1, 0xa4, 0xb4, 0x18, 0xac, 0x81, 0xcf, 0xc8, 0x50, 0x0f, 0xd5, |
315 | 0x22, 0x3d, 0x2c, 0x9a, 0xf4, 0x82, 0x41, 0x86, 0xe6, 0xa5, 0x07, 0x83, 0x35, 0x06, 0x41, 0x0d, | ||
316 | 0x50, 0xf2, 0xe7, 0xe2, 0x45, 0x91, 0x10, 0xe2, 0xe6, 0x62, 0x0f, 0xf5, 0xf3, 0xf6, 0xf3, 0x0f, | ||
317 | 0xf7, 0x13, 0x60, 0x00, 0x71, 0x82, 0x5d, 0x83, 0xc2, 0x3c, 0xfd, 0xdc, 0x05, 0x18, 0x85, 0xf8, | ||
318 | 0xb9, 0xb8, 0xfd, 0xfc, 0x43, 0xe2, 0x61, 0x02, 0x4c, 0x42, 0xc2, 0x5c, 0xfc, 0x60, 0x8e, 0xb3, | ||
319 | 0x6b, 0x3c, 0x4c, 0x0b, 0xb3, 0xd1, 0x3a, 0x46, 0x2e, 0x36, 0x88, 0xf5, 0x42, 0x01, 0x5c, 0xac, | ||
320 | 0x60, 0x27, 0x08, 0x29, 0xe1, 0x75, 0x1f, 0x38, 0x14, 0xa4, 0x94, 0x89, 0xf0, 0x83, 0x50, 0x10, | ||
321 | 0x17, 0x6b, 0x78, 0x62, 0x49, 0x72, 0x06, 0xd5, 0x4c, 0x34, 0x60, 0x74, 0x4a, 0xe4, 0x12, 0xcc, | ||
322 | 0xcc, 0x47, 0x53, 0xea, 0xc4, 0x0d, 0x51, 0x1b, 0x00, 0x8a, 0xc6, 0x00, 0xc6, 0x28, 0x9d, 0xf4, | ||
323 | 0xfc, 0xfc, 0xf4, 0x9c, 0x54, 0xbd, 0xf4, 0xfc, 0x9c, 0xc4, 0xbc, 0x74, 0xbd, 0xfc, 0xa2, 0x74, | ||
324 | 0x7d, 0xe4, 0x78, 0x07, 0xb1, 0xe3, 0x21, 0xec, 0xf8, 0x32, 0xc3, 0x55, 0x4c, 0x7c, 0xee, 0x20, | ||
325 | 0xd3, 0x20, 0x46, 0xe8, 0x85, 0x19, 0x26, 0xb1, 0x81, 0x93, 0x83, 0x31, 0x20, 0x00, 0x00, 0xff, | ||
326 | 0xff, 0x12, 0x7d, 0x96, 0xcb, 0x2d, 0x02, 0x00, 0x00, | ||
176 | } | 327 | } |
diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.proto b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.proto deleted file mode 100644 index 6072fdc..0000000 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.proto +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | // Copyright 2017 gRPC authors. | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | syntax = "proto3"; | ||
16 | |||
17 | package grpc.health.v1; | ||
18 | |||
19 | message HealthCheckRequest { | ||
20 | string service = 1; | ||
21 | } | ||
22 | |||
23 | message HealthCheckResponse { | ||
24 | enum ServingStatus { | ||
25 | UNKNOWN = 0; | ||
26 | SERVING = 1; | ||
27 | NOT_SERVING = 2; | ||
28 | } | ||
29 | ServingStatus status = 1; | ||
30 | } | ||
31 | |||
32 | service Health{ | ||
33 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); | ||
34 | } | ||
diff --git a/vendor/google.golang.org/grpc/health/health.go b/vendor/google.golang.org/grpc/health/health.go deleted file mode 100644 index 4dccbc7..0000000 --- a/vendor/google.golang.org/grpc/health/health.go +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package health provides some utility functions to health-check a server. The implementation | ||
20 | // is based on protobuf. Users need to write their own implementations if other IDLs are used. | ||
21 | package health | ||
22 | |||
23 | import ( | ||
24 | "sync" | ||
25 | |||
26 | "golang.org/x/net/context" | ||
27 | "google.golang.org/grpc" | ||
28 | "google.golang.org/grpc/codes" | ||
29 | healthpb "google.golang.org/grpc/health/grpc_health_v1" | ||
30 | ) | ||
31 | |||
32 | // Server implements `service Health`. | ||
33 | type Server struct { | ||
34 | mu sync.Mutex | ||
35 | // statusMap stores the serving status of the services this Server monitors. | ||
36 | statusMap map[string]healthpb.HealthCheckResponse_ServingStatus | ||
37 | } | ||
38 | |||
39 | // NewServer returns a new Server. | ||
40 | func NewServer() *Server { | ||
41 | return &Server{ | ||
42 | statusMap: make(map[string]healthpb.HealthCheckResponse_ServingStatus), | ||
43 | } | ||
44 | } | ||
45 | |||
46 | // Check implements `service Health`. | ||
47 | func (s *Server) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) { | ||
48 | s.mu.Lock() | ||
49 | defer s.mu.Unlock() | ||
50 | if in.Service == "" { | ||
51 | // check the server overall health status. | ||
52 | return &healthpb.HealthCheckResponse{ | ||
53 | Status: healthpb.HealthCheckResponse_SERVING, | ||
54 | }, nil | ||
55 | } | ||
56 | if status, ok := s.statusMap[in.Service]; ok { | ||
57 | return &healthpb.HealthCheckResponse{ | ||
58 | Status: status, | ||
59 | }, nil | ||
60 | } | ||
61 | return nil, grpc.Errorf(codes.NotFound, "unknown service") | ||
62 | } | ||
63 | |||
64 | // SetServingStatus is called when need to reset the serving status of a service | ||
65 | // or insert a new service entry into the statusMap. | ||
66 | func (s *Server) SetServingStatus(service string, status healthpb.HealthCheckResponse_ServingStatus) { | ||
67 | s.mu.Lock() | ||
68 | s.statusMap[service] = status | ||
69 | s.mu.Unlock() | ||
70 | } | ||
diff --git a/vendor/google.golang.org/grpc/health/regenerate.sh b/vendor/google.golang.org/grpc/health/regenerate.sh new file mode 100644 index 0000000..b11eccb --- /dev/null +++ b/vendor/google.golang.org/grpc/health/regenerate.sh | |||
@@ -0,0 +1,33 @@ | |||
1 | #!/bin/bash | ||
2 | # Copyright 2018 gRPC authors. | ||
3 | # | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | # you may not use this file except in compliance with the License. | ||
6 | # You may obtain a copy of the License at | ||
7 | # | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | # | ||
10 | # Unless required by applicable law or agreed to in writing, software | ||
11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | # See the License for the specific language governing permissions and | ||
14 | # limitations under the License. | ||
15 | |||
16 | set -eux -o pipefail | ||
17 | |||
18 | TMP=$(mktemp -d) | ||
19 | |||
20 | function finish { | ||
21 | rm -rf "$TMP" | ||
22 | } | ||
23 | trap finish EXIT | ||
24 | |||
25 | pushd "$TMP" | ||
26 | mkdir -p grpc/health/v1 | ||
27 | curl https://raw.githubusercontent.com/grpc/grpc-proto/master/grpc/health/v1/health.proto > grpc/health/v1/health.proto | ||
28 | |||
29 | protoc --go_out=plugins=grpc,paths=source_relative:. -I. grpc/health/v1/*.proto | ||
30 | popd | ||
31 | rm -f grpc_health_v1/*.pb.go | ||
32 | cp "$TMP"/grpc/health/v1/*.pb.go grpc_health_v1/ | ||
33 | |||
diff --git a/vendor/google.golang.org/grpc/health/server.go b/vendor/google.golang.org/grpc/health/server.go new file mode 100644 index 0000000..c79f9d2 --- /dev/null +++ b/vendor/google.golang.org/grpc/health/server.go | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | //go:generate ./regenerate.sh | ||
20 | |||
21 | // Package health provides a service that exposes server's health and it must be | ||
22 | // imported to enable support for client-side health checks. | ||
23 | package health | ||
24 | |||
25 | import ( | ||
26 | "context" | ||
27 | "sync" | ||
28 | |||
29 | "google.golang.org/grpc/codes" | ||
30 | "google.golang.org/grpc/grpclog" | ||
31 | healthgrpc "google.golang.org/grpc/health/grpc_health_v1" | ||
32 | healthpb "google.golang.org/grpc/health/grpc_health_v1" | ||
33 | "google.golang.org/grpc/status" | ||
34 | ) | ||
35 | |||
36 | // Server implements `service Health`. | ||
37 | type Server struct { | ||
38 | mu sync.Mutex | ||
39 | // If shutdown is true, it's expected all serving status is NOT_SERVING, and | ||
40 | // will stay in NOT_SERVING. | ||
41 | shutdown bool | ||
42 | // statusMap stores the serving status of the services this Server monitors. | ||
43 | statusMap map[string]healthpb.HealthCheckResponse_ServingStatus | ||
44 | updates map[string]map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus | ||
45 | } | ||
46 | |||
47 | // NewServer returns a new Server. | ||
48 | func NewServer() *Server { | ||
49 | return &Server{ | ||
50 | statusMap: map[string]healthpb.HealthCheckResponse_ServingStatus{"": healthpb.HealthCheckResponse_SERVING}, | ||
51 | updates: make(map[string]map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus), | ||
52 | } | ||
53 | } | ||
54 | |||
55 | // Check implements `service Health`. | ||
56 | func (s *Server) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) { | ||
57 | s.mu.Lock() | ||
58 | defer s.mu.Unlock() | ||
59 | if servingStatus, ok := s.statusMap[in.Service]; ok { | ||
60 | return &healthpb.HealthCheckResponse{ | ||
61 | Status: servingStatus, | ||
62 | }, nil | ||
63 | } | ||
64 | return nil, status.Error(codes.NotFound, "unknown service") | ||
65 | } | ||
66 | |||
67 | // Watch implements `service Health`. | ||
68 | func (s *Server) Watch(in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { | ||
69 | service := in.Service | ||
70 | // update channel is used for getting service status updates. | ||
71 | update := make(chan healthpb.HealthCheckResponse_ServingStatus, 1) | ||
72 | s.mu.Lock() | ||
73 | // Puts the initial status to the channel. | ||
74 | if servingStatus, ok := s.statusMap[service]; ok { | ||
75 | update <- servingStatus | ||
76 | } else { | ||
77 | update <- healthpb.HealthCheckResponse_SERVICE_UNKNOWN | ||
78 | } | ||
79 | |||
80 | // Registers the update channel to the correct place in the updates map. | ||
81 | if _, ok := s.updates[service]; !ok { | ||
82 | s.updates[service] = make(map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus) | ||
83 | } | ||
84 | s.updates[service][stream] = update | ||
85 | defer func() { | ||
86 | s.mu.Lock() | ||
87 | delete(s.updates[service], stream) | ||
88 | s.mu.Unlock() | ||
89 | }() | ||
90 | s.mu.Unlock() | ||
91 | |||
92 | var lastSentStatus healthpb.HealthCheckResponse_ServingStatus = -1 | ||
93 | for { | ||
94 | select { | ||
95 | // Status updated. Sends the up-to-date status to the client. | ||
96 | case servingStatus := <-update: | ||
97 | if lastSentStatus == servingStatus { | ||
98 | continue | ||
99 | } | ||
100 | lastSentStatus = servingStatus | ||
101 | err := stream.Send(&healthpb.HealthCheckResponse{Status: servingStatus}) | ||
102 | if err != nil { | ||
103 | return status.Error(codes.Canceled, "Stream has ended.") | ||
104 | } | ||
105 | // Context done. Removes the update channel from the updates map. | ||
106 | case <-stream.Context().Done(): | ||
107 | return status.Error(codes.Canceled, "Stream has ended.") | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // SetServingStatus is called when need to reset the serving status of a service | ||
113 | // or insert a new service entry into the statusMap. | ||
114 | func (s *Server) SetServingStatus(service string, servingStatus healthpb.HealthCheckResponse_ServingStatus) { | ||
115 | s.mu.Lock() | ||
116 | defer s.mu.Unlock() | ||
117 | if s.shutdown { | ||
118 | grpclog.Infof("health: status changing for %s to %v is ignored because health service is shutdown", service, servingStatus) | ||
119 | return | ||
120 | } | ||
121 | |||
122 | s.setServingStatusLocked(service, servingStatus) | ||
123 | } | ||
124 | |||
125 | func (s *Server) setServingStatusLocked(service string, servingStatus healthpb.HealthCheckResponse_ServingStatus) { | ||
126 | s.statusMap[service] = servingStatus | ||
127 | for _, update := range s.updates[service] { | ||
128 | // Clears previous updates, that are not sent to the client, from the channel. | ||
129 | // This can happen if the client is not reading and the server gets flow control limited. | ||
130 | select { | ||
131 | case <-update: | ||
132 | default: | ||
133 | } | ||
134 | // Puts the most recent update to the channel. | ||
135 | update <- servingStatus | ||
136 | } | ||
137 | } | ||
138 | |||
139 | // Shutdown sets all serving status to NOT_SERVING, and configures the server to | ||
140 | // ignore all future status changes. | ||
141 | // | ||
142 | // This changes serving status for all services. To set status for a perticular | ||
143 | // services, call SetServingStatus(). | ||
144 | func (s *Server) Shutdown() { | ||
145 | s.mu.Lock() | ||
146 | defer s.mu.Unlock() | ||
147 | s.shutdown = true | ||
148 | for service := range s.statusMap { | ||
149 | s.setServingStatusLocked(service, healthpb.HealthCheckResponse_NOT_SERVING) | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // Resume sets all serving status to SERVING, and configures the server to | ||
154 | // accept all future status changes. | ||
155 | // | ||
156 | // This changes serving status for all services. To set status for a perticular | ||
157 | // services, call SetServingStatus(). | ||
158 | func (s *Server) Resume() { | ||
159 | s.mu.Lock() | ||
160 | defer s.mu.Unlock() | ||
161 | s.shutdown = false | ||
162 | for service := range s.statusMap { | ||
163 | s.setServingStatusLocked(service, healthpb.HealthCheckResponse_SERVING) | ||
164 | } | ||
165 | } | ||
diff --git a/vendor/google.golang.org/grpc/install_gae.sh b/vendor/google.golang.org/grpc/install_gae.sh new file mode 100644 index 0000000..7c7bcad --- /dev/null +++ b/vendor/google.golang.org/grpc/install_gae.sh | |||
@@ -0,0 +1,6 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TMP=$(mktemp -d /tmp/sdk.XXX) \ | ||
4 | && curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \ | ||
5 | && unzip -q $TMP.zip -d $TMP \ | ||
6 | && export PATH="$PATH:$TMP/go_appengine" | ||
diff --git a/vendor/google.golang.org/grpc/interceptor.go b/vendor/google.golang.org/grpc/interceptor.go index 06dc825..8b73500 100644 --- a/vendor/google.golang.org/grpc/interceptor.go +++ b/vendor/google.golang.org/grpc/interceptor.go | |||
@@ -19,7 +19,7 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "golang.org/x/net/context" | 22 | "context" |
23 | ) | 23 | ) |
24 | 24 | ||
25 | // UnaryInvoker is called by UnaryClientInterceptor to complete RPCs. | 25 | // UnaryInvoker is called by UnaryClientInterceptor to complete RPCs. |
@@ -48,7 +48,9 @@ type UnaryServerInfo struct { | |||
48 | } | 48 | } |
49 | 49 | ||
50 | // UnaryHandler defines the handler invoked by UnaryServerInterceptor to complete the normal | 50 | // UnaryHandler defines the handler invoked by UnaryServerInterceptor to complete the normal |
51 | // execution of a unary RPC. | 51 | // execution of a unary RPC. If a UnaryHandler returns an error, it should be produced by the |
52 | // status package, or else gRPC will use codes.Unknown as the status code and err.Error() as | ||
53 | // the status message of the RPC. | ||
52 | type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error) | 54 | type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error) |
53 | 55 | ||
54 | // UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info | 56 | // UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info |
diff --git a/vendor/google.golang.org/grpc/internal/backoff/backoff.go b/vendor/google.golang.org/grpc/internal/backoff/backoff.go new file mode 100644 index 0000000..1bd0cce --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/backoff/backoff.go | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package backoff implement the backoff strategy for gRPC. | ||
20 | // | ||
21 | // This is kept in internal until the gRPC project decides whether or not to | ||
22 | // allow alternative backoff strategies. | ||
23 | package backoff | ||
24 | |||
25 | import ( | ||
26 | "time" | ||
27 | |||
28 | "google.golang.org/grpc/internal/grpcrand" | ||
29 | ) | ||
30 | |||
31 | // Strategy defines the methodology for backing off after a grpc connection | ||
32 | // failure. | ||
33 | // | ||
34 | type Strategy interface { | ||
35 | // Backoff returns the amount of time to wait before the next retry given | ||
36 | // the number of consecutive failures. | ||
37 | Backoff(retries int) time.Duration | ||
38 | } | ||
39 | |||
40 | const ( | ||
41 | // baseDelay is the amount of time to wait before retrying after the first | ||
42 | // failure. | ||
43 | baseDelay = 1.0 * time.Second | ||
44 | // factor is applied to the backoff after each retry. | ||
45 | factor = 1.6 | ||
46 | // jitter provides a range to randomize backoff delays. | ||
47 | jitter = 0.2 | ||
48 | ) | ||
49 | |||
50 | // Exponential implements exponential backoff algorithm as defined in | ||
51 | // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. | ||
52 | type Exponential struct { | ||
53 | // MaxDelay is the upper bound of backoff delay. | ||
54 | MaxDelay time.Duration | ||
55 | } | ||
56 | |||
57 | // Backoff returns the amount of time to wait before the next retry given the | ||
58 | // number of retries. | ||
59 | func (bc Exponential) Backoff(retries int) time.Duration { | ||
60 | if retries == 0 { | ||
61 | return baseDelay | ||
62 | } | ||
63 | backoff, max := float64(baseDelay), float64(bc.MaxDelay) | ||
64 | for backoff < max && retries > 0 { | ||
65 | backoff *= factor | ||
66 | retries-- | ||
67 | } | ||
68 | if backoff > max { | ||
69 | backoff = max | ||
70 | } | ||
71 | // Randomize backoff delays so that if a cluster of requests start at | ||
72 | // the same time, they won't operate in lockstep. | ||
73 | backoff *= 1 + jitter*(grpcrand.Float64()*2-1) | ||
74 | if backoff < 0 { | ||
75 | return 0 | ||
76 | } | ||
77 | return time.Duration(backoff) | ||
78 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go new file mode 100644 index 0000000..fee6aec --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package binarylog implementation binary logging as defined in | ||
20 | // https://github.com/grpc/proposal/blob/master/A16-binary-logging.md. | ||
21 | package binarylog | ||
22 | |||
23 | import ( | ||
24 | "fmt" | ||
25 | "os" | ||
26 | |||
27 | "google.golang.org/grpc/grpclog" | ||
28 | ) | ||
29 | |||
30 | // Logger is the global binary logger. It can be used to get binary logger for | ||
31 | // each method. | ||
32 | type Logger interface { | ||
33 | getMethodLogger(methodName string) *MethodLogger | ||
34 | } | ||
35 | |||
36 | // binLogger is the global binary logger for the binary. One of this should be | ||
37 | // built at init time from the configuration (environment varialbe or flags). | ||
38 | // | ||
39 | // It is used to get a methodLogger for each individual method. | ||
40 | var binLogger Logger | ||
41 | |||
42 | // SetLogger sets the binarg logger. | ||
43 | // | ||
44 | // Only call this at init time. | ||
45 | func SetLogger(l Logger) { | ||
46 | binLogger = l | ||
47 | } | ||
48 | |||
49 | // GetMethodLogger returns the methodLogger for the given methodName. | ||
50 | // | ||
51 | // methodName should be in the format of "/service/method". | ||
52 | // | ||
53 | // Each methodLogger returned by this method is a new instance. This is to | ||
54 | // generate sequence id within the call. | ||
55 | func GetMethodLogger(methodName string) *MethodLogger { | ||
56 | if binLogger == nil { | ||
57 | return nil | ||
58 | } | ||
59 | return binLogger.getMethodLogger(methodName) | ||
60 | } | ||
61 | |||
62 | func init() { | ||
63 | const envStr = "GRPC_BINARY_LOG_FILTER" | ||
64 | configStr := os.Getenv(envStr) | ||
65 | binLogger = NewLoggerFromConfigString(configStr) | ||
66 | } | ||
67 | |||
68 | type methodLoggerConfig struct { | ||
69 | // Max length of header and message. | ||
70 | hdr, msg uint64 | ||
71 | } | ||
72 | |||
73 | type logger struct { | ||
74 | all *methodLoggerConfig | ||
75 | services map[string]*methodLoggerConfig | ||
76 | methods map[string]*methodLoggerConfig | ||
77 | |||
78 | blacklist map[string]struct{} | ||
79 | } | ||
80 | |||
81 | // newEmptyLogger creates an empty logger. The map fields need to be filled in | ||
82 | // using the set* functions. | ||
83 | func newEmptyLogger() *logger { | ||
84 | return &logger{} | ||
85 | } | ||
86 | |||
87 | // Set method logger for "*". | ||
88 | func (l *logger) setDefaultMethodLogger(ml *methodLoggerConfig) error { | ||
89 | if l.all != nil { | ||
90 | return fmt.Errorf("conflicting global rules found") | ||
91 | } | ||
92 | l.all = ml | ||
93 | return nil | ||
94 | } | ||
95 | |||
96 | // Set method logger for "service/*". | ||
97 | // | ||
98 | // New methodLogger with same service overrides the old one. | ||
99 | func (l *logger) setServiceMethodLogger(service string, ml *methodLoggerConfig) error { | ||
100 | if _, ok := l.services[service]; ok { | ||
101 | return fmt.Errorf("conflicting rules for service %v found", service) | ||
102 | } | ||
103 | if l.services == nil { | ||
104 | l.services = make(map[string]*methodLoggerConfig) | ||
105 | } | ||
106 | l.services[service] = ml | ||
107 | return nil | ||
108 | } | ||
109 | |||
110 | // Set method logger for "service/method". | ||
111 | // | ||
112 | // New methodLogger with same method overrides the old one. | ||
113 | func (l *logger) setMethodMethodLogger(method string, ml *methodLoggerConfig) error { | ||
114 | if _, ok := l.blacklist[method]; ok { | ||
115 | return fmt.Errorf("conflicting rules for method %v found", method) | ||
116 | } | ||
117 | if _, ok := l.methods[method]; ok { | ||
118 | return fmt.Errorf("conflicting rules for method %v found", method) | ||
119 | } | ||
120 | if l.methods == nil { | ||
121 | l.methods = make(map[string]*methodLoggerConfig) | ||
122 | } | ||
123 | l.methods[method] = ml | ||
124 | return nil | ||
125 | } | ||
126 | |||
127 | // Set blacklist method for "-service/method". | ||
128 | func (l *logger) setBlacklist(method string) error { | ||
129 | if _, ok := l.blacklist[method]; ok { | ||
130 | return fmt.Errorf("conflicting rules for method %v found", method) | ||
131 | } | ||
132 | if _, ok := l.methods[method]; ok { | ||
133 | return fmt.Errorf("conflicting rules for method %v found", method) | ||
134 | } | ||
135 | if l.blacklist == nil { | ||
136 | l.blacklist = make(map[string]struct{}) | ||
137 | } | ||
138 | l.blacklist[method] = struct{}{} | ||
139 | return nil | ||
140 | } | ||
141 | |||
142 | // getMethodLogger returns the methodLogger for the given methodName. | ||
143 | // | ||
144 | // methodName should be in the format of "/service/method". | ||
145 | // | ||
146 | // Each methodLogger returned by this method is a new instance. This is to | ||
147 | // generate sequence id within the call. | ||
148 | func (l *logger) getMethodLogger(methodName string) *MethodLogger { | ||
149 | s, m, err := parseMethodName(methodName) | ||
150 | if err != nil { | ||
151 | grpclog.Infof("binarylogging: failed to parse %q: %v", methodName, err) | ||
152 | return nil | ||
153 | } | ||
154 | if ml, ok := l.methods[s+"/"+m]; ok { | ||
155 | return newMethodLogger(ml.hdr, ml.msg) | ||
156 | } | ||
157 | if _, ok := l.blacklist[s+"/"+m]; ok { | ||
158 | return nil | ||
159 | } | ||
160 | if ml, ok := l.services[s]; ok { | ||
161 | return newMethodLogger(ml.hdr, ml.msg) | ||
162 | } | ||
163 | if l.all == nil { | ||
164 | return nil | ||
165 | } | ||
166 | return newMethodLogger(l.all.hdr, l.all.msg) | ||
167 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go new file mode 100644 index 0000000..1ee00a3 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // This file contains exported variables/functions that are exported for testing | ||
20 | // only. | ||
21 | // | ||
22 | // An ideal way for this would be to put those in a *_test.go but in binarylog | ||
23 | // package. But this doesn't work with staticcheck with go module. Error was: | ||
24 | // "MdToMetadataProto not declared by package binarylog". This could be caused | ||
25 | // by the way staticcheck looks for files for a certain package, which doesn't | ||
26 | // support *_test.go files. | ||
27 | // | ||
28 | // Move those to binary_test.go when staticcheck is fixed. | ||
29 | |||
30 | package binarylog | ||
31 | |||
32 | var ( | ||
33 | // AllLogger is a logger that logs all headers/messages for all RPCs. It's | ||
34 | // for testing only. | ||
35 | AllLogger = NewLoggerFromConfigString("*") | ||
36 | // MdToMetadataProto converts metadata to a binary logging proto message. | ||
37 | // It's for testing only. | ||
38 | MdToMetadataProto = mdToMetadataProto | ||
39 | // AddrToProto converts an address to a binary logging proto message. It's | ||
40 | // for testing only. | ||
41 | AddrToProto = addrToProto | ||
42 | ) | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go new file mode 100644 index 0000000..eb188ea --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package binarylog | ||
20 | |||
21 | import ( | ||
22 | "errors" | ||
23 | "fmt" | ||
24 | "regexp" | ||
25 | "strconv" | ||
26 | "strings" | ||
27 | |||
28 | "google.golang.org/grpc/grpclog" | ||
29 | ) | ||
30 | |||
31 | // NewLoggerFromConfigString reads the string and build a logger. It can be used | ||
32 | // to build a new logger and assign it to binarylog.Logger. | ||
33 | // | ||
34 | // Example filter config strings: | ||
35 | // - "" Nothing will be logged | ||
36 | // - "*" All headers and messages will be fully logged. | ||
37 | // - "*{h}" Only headers will be logged. | ||
38 | // - "*{m:256}" Only the first 256 bytes of each message will be logged. | ||
39 | // - "Foo/*" Logs every method in service Foo | ||
40 | // - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar | ||
41 | // - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method | ||
42 | // /Foo/Bar, logs all headers and messages in every other method in service | ||
43 | // Foo. | ||
44 | // | ||
45 | // If two configs exist for one certain method or service, the one specified | ||
46 | // later overrides the privous config. | ||
47 | func NewLoggerFromConfigString(s string) Logger { | ||
48 | if s == "" { | ||
49 | return nil | ||
50 | } | ||
51 | l := newEmptyLogger() | ||
52 | methods := strings.Split(s, ",") | ||
53 | for _, method := range methods { | ||
54 | if err := l.fillMethodLoggerWithConfigString(method); err != nil { | ||
55 | grpclog.Warningf("failed to parse binary log config: %v", err) | ||
56 | return nil | ||
57 | } | ||
58 | } | ||
59 | return l | ||
60 | } | ||
61 | |||
62 | // fillMethodLoggerWithConfigString parses config, creates methodLogger and adds | ||
63 | // it to the right map in the logger. | ||
64 | func (l *logger) fillMethodLoggerWithConfigString(config string) error { | ||
65 | // "" is invalid. | ||
66 | if config == "" { | ||
67 | return errors.New("empty string is not a valid method binary logging config") | ||
68 | } | ||
69 | |||
70 | // "-service/method", blacklist, no * or {} allowed. | ||
71 | if config[0] == '-' { | ||
72 | s, m, suffix, err := parseMethodConfigAndSuffix(config[1:]) | ||
73 | if err != nil { | ||
74 | return fmt.Errorf("invalid config: %q, %v", config, err) | ||
75 | } | ||
76 | if m == "*" { | ||
77 | return fmt.Errorf("invalid config: %q, %v", config, "* not allowd in blacklist config") | ||
78 | } | ||
79 | if suffix != "" { | ||
80 | return fmt.Errorf("invalid config: %q, %v", config, "header/message limit not allowed in blacklist config") | ||
81 | } | ||
82 | if err := l.setBlacklist(s + "/" + m); err != nil { | ||
83 | return fmt.Errorf("invalid config: %v", err) | ||
84 | } | ||
85 | return nil | ||
86 | } | ||
87 | |||
88 | // "*{h:256;m:256}" | ||
89 | if config[0] == '*' { | ||
90 | hdr, msg, err := parseHeaderMessageLengthConfig(config[1:]) | ||
91 | if err != nil { | ||
92 | return fmt.Errorf("invalid config: %q, %v", config, err) | ||
93 | } | ||
94 | if err := l.setDefaultMethodLogger(&methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { | ||
95 | return fmt.Errorf("invalid config: %v", err) | ||
96 | } | ||
97 | return nil | ||
98 | } | ||
99 | |||
100 | s, m, suffix, err := parseMethodConfigAndSuffix(config) | ||
101 | if err != nil { | ||
102 | return fmt.Errorf("invalid config: %q, %v", config, err) | ||
103 | } | ||
104 | hdr, msg, err := parseHeaderMessageLengthConfig(suffix) | ||
105 | if err != nil { | ||
106 | return fmt.Errorf("invalid header/message length config: %q, %v", suffix, err) | ||
107 | } | ||
108 | if m == "*" { | ||
109 | if err := l.setServiceMethodLogger(s, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { | ||
110 | return fmt.Errorf("invalid config: %v", err) | ||
111 | } | ||
112 | } else { | ||
113 | if err := l.setMethodMethodLogger(s+"/"+m, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { | ||
114 | return fmt.Errorf("invalid config: %v", err) | ||
115 | } | ||
116 | } | ||
117 | return nil | ||
118 | } | ||
119 | |||
120 | const ( | ||
121 | // TODO: this const is only used by env_config now. But could be useful for | ||
122 | // other config. Move to binarylog.go if necessary. | ||
123 | maxUInt = ^uint64(0) | ||
124 | |||
125 | // For "p.s/m" plus any suffix. Suffix will be parsed again. See test for | ||
126 | // expected output. | ||
127 | longMethodConfigRegexpStr = `^([\w./]+)/((?:\w+)|[*])(.+)?$` | ||
128 | |||
129 | // For suffix from above, "{h:123,m:123}". See test for expected output. | ||
130 | optionalLengthRegexpStr = `(?::(\d+))?` // Optional ":123". | ||
131 | headerConfigRegexpStr = `^{h` + optionalLengthRegexpStr + `}$` | ||
132 | messageConfigRegexpStr = `^{m` + optionalLengthRegexpStr + `}$` | ||
133 | headerMessageConfigRegexpStr = `^{h` + optionalLengthRegexpStr + `;m` + optionalLengthRegexpStr + `}$` | ||
134 | ) | ||
135 | |||
136 | var ( | ||
137 | longMethodConfigRegexp = regexp.MustCompile(longMethodConfigRegexpStr) | ||
138 | headerConfigRegexp = regexp.MustCompile(headerConfigRegexpStr) | ||
139 | messageConfigRegexp = regexp.MustCompile(messageConfigRegexpStr) | ||
140 | headerMessageConfigRegexp = regexp.MustCompile(headerMessageConfigRegexpStr) | ||
141 | ) | ||
142 | |||
143 | // Turn "service/method{h;m}" into "service", "method", "{h;m}". | ||
144 | func parseMethodConfigAndSuffix(c string) (service, method, suffix string, _ error) { | ||
145 | // Regexp result: | ||
146 | // | ||
147 | // in: "p.s/m{h:123,m:123}", | ||
148 | // out: []string{"p.s/m{h:123,m:123}", "p.s", "m", "{h:123,m:123}"}, | ||
149 | match := longMethodConfigRegexp.FindStringSubmatch(c) | ||
150 | if match == nil { | ||
151 | return "", "", "", fmt.Errorf("%q contains invalid substring", c) | ||
152 | } | ||
153 | service = match[1] | ||
154 | method = match[2] | ||
155 | suffix = match[3] | ||
156 | return | ||
157 | } | ||
158 | |||
159 | // Turn "{h:123;m:345}" into 123, 345. | ||
160 | // | ||
161 | // Return maxUInt if length is unspecified. | ||
162 | func parseHeaderMessageLengthConfig(c string) (hdrLenStr, msgLenStr uint64, err error) { | ||
163 | if c == "" { | ||
164 | return maxUInt, maxUInt, nil | ||
165 | } | ||
166 | // Header config only. | ||
167 | if match := headerConfigRegexp.FindStringSubmatch(c); match != nil { | ||
168 | if s := match[1]; s != "" { | ||
169 | hdrLenStr, err = strconv.ParseUint(s, 10, 64) | ||
170 | if err != nil { | ||
171 | return 0, 0, fmt.Errorf("failed to convert %q to uint", s) | ||
172 | } | ||
173 | return hdrLenStr, 0, nil | ||
174 | } | ||
175 | return maxUInt, 0, nil | ||
176 | } | ||
177 | |||
178 | // Message config only. | ||
179 | if match := messageConfigRegexp.FindStringSubmatch(c); match != nil { | ||
180 | if s := match[1]; s != "" { | ||
181 | msgLenStr, err = strconv.ParseUint(s, 10, 64) | ||
182 | if err != nil { | ||
183 | return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) | ||
184 | } | ||
185 | return 0, msgLenStr, nil | ||
186 | } | ||
187 | return 0, maxUInt, nil | ||
188 | } | ||
189 | |||
190 | // Header and message config both. | ||
191 | if match := headerMessageConfigRegexp.FindStringSubmatch(c); match != nil { | ||
192 | // Both hdr and msg are specified, but one or two of them might be empty. | ||
193 | hdrLenStr = maxUInt | ||
194 | msgLenStr = maxUInt | ||
195 | if s := match[1]; s != "" { | ||
196 | hdrLenStr, err = strconv.ParseUint(s, 10, 64) | ||
197 | if err != nil { | ||
198 | return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) | ||
199 | } | ||
200 | } | ||
201 | if s := match[2]; s != "" { | ||
202 | msgLenStr, err = strconv.ParseUint(s, 10, 64) | ||
203 | if err != nil { | ||
204 | return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) | ||
205 | } | ||
206 | } | ||
207 | return hdrLenStr, msgLenStr, nil | ||
208 | } | ||
209 | return 0, 0, fmt.Errorf("%q contains invalid substring", c) | ||
210 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go new file mode 100644 index 0000000..b06cdd4 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go | |||
@@ -0,0 +1,426 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package binarylog | ||
20 | |||
21 | import ( | ||
22 | "net" | ||
23 | "strings" | ||
24 | "sync/atomic" | ||
25 | "time" | ||
26 | |||
27 | "github.com/golang/protobuf/proto" | ||
28 | "github.com/golang/protobuf/ptypes" | ||
29 | pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" | ||
30 | "google.golang.org/grpc/grpclog" | ||
31 | "google.golang.org/grpc/metadata" | ||
32 | "google.golang.org/grpc/status" | ||
33 | ) | ||
34 | |||
35 | type callIDGenerator struct { | ||
36 | id uint64 | ||
37 | } | ||
38 | |||
39 | func (g *callIDGenerator) next() uint64 { | ||
40 | id := atomic.AddUint64(&g.id, 1) | ||
41 | return id | ||
42 | } | ||
43 | |||
44 | // reset is for testing only, and doesn't need to be thread safe. | ||
45 | func (g *callIDGenerator) reset() { | ||
46 | g.id = 0 | ||
47 | } | ||
48 | |||
49 | var idGen callIDGenerator | ||
50 | |||
51 | // MethodLogger is the sub-logger for each method. | ||
52 | type MethodLogger struct { | ||
53 | headerMaxLen, messageMaxLen uint64 | ||
54 | |||
55 | callID uint64 | ||
56 | idWithinCallGen *callIDGenerator | ||
57 | |||
58 | sink Sink // TODO(blog): make this plugable. | ||
59 | } | ||
60 | |||
61 | func newMethodLogger(h, m uint64) *MethodLogger { | ||
62 | return &MethodLogger{ | ||
63 | headerMaxLen: h, | ||
64 | messageMaxLen: m, | ||
65 | |||
66 | callID: idGen.next(), | ||
67 | idWithinCallGen: &callIDGenerator{}, | ||
68 | |||
69 | sink: defaultSink, // TODO(blog): make it plugable. | ||
70 | } | ||
71 | } | ||
72 | |||
73 | // Log creates a proto binary log entry, and logs it to the sink. | ||
74 | func (ml *MethodLogger) Log(c LogEntryConfig) { | ||
75 | m := c.toProto() | ||
76 | timestamp, _ := ptypes.TimestampProto(time.Now()) | ||
77 | m.Timestamp = timestamp | ||
78 | m.CallId = ml.callID | ||
79 | m.SequenceIdWithinCall = ml.idWithinCallGen.next() | ||
80 | |||
81 | switch pay := m.Payload.(type) { | ||
82 | case *pb.GrpcLogEntry_ClientHeader: | ||
83 | m.PayloadTruncated = ml.truncateMetadata(pay.ClientHeader.GetMetadata()) | ||
84 | case *pb.GrpcLogEntry_ServerHeader: | ||
85 | m.PayloadTruncated = ml.truncateMetadata(pay.ServerHeader.GetMetadata()) | ||
86 | case *pb.GrpcLogEntry_Message: | ||
87 | m.PayloadTruncated = ml.truncateMessage(pay.Message) | ||
88 | } | ||
89 | |||
90 | ml.sink.Write(m) | ||
91 | } | ||
92 | |||
93 | func (ml *MethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { | ||
94 | if ml.headerMaxLen == maxUInt { | ||
95 | return false | ||
96 | } | ||
97 | var ( | ||
98 | bytesLimit = ml.headerMaxLen | ||
99 | index int | ||
100 | ) | ||
101 | // At the end of the loop, index will be the first entry where the total | ||
102 | // size is greater than the limit: | ||
103 | // | ||
104 | // len(entry[:index]) <= ml.hdr && len(entry[:index+1]) > ml.hdr. | ||
105 | for ; index < len(mdPb.Entry); index++ { | ||
106 | entry := mdPb.Entry[index] | ||
107 | if entry.Key == "grpc-trace-bin" { | ||
108 | // "grpc-trace-bin" is a special key. It's kept in the log entry, | ||
109 | // but not counted towards the size limit. | ||
110 | continue | ||
111 | } | ||
112 | currentEntryLen := uint64(len(entry.Value)) | ||
113 | if currentEntryLen > bytesLimit { | ||
114 | break | ||
115 | } | ||
116 | bytesLimit -= currentEntryLen | ||
117 | } | ||
118 | truncated = index < len(mdPb.Entry) | ||
119 | mdPb.Entry = mdPb.Entry[:index] | ||
120 | return truncated | ||
121 | } | ||
122 | |||
123 | func (ml *MethodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { | ||
124 | if ml.messageMaxLen == maxUInt { | ||
125 | return false | ||
126 | } | ||
127 | if ml.messageMaxLen >= uint64(len(msgPb.Data)) { | ||
128 | return false | ||
129 | } | ||
130 | msgPb.Data = msgPb.Data[:ml.messageMaxLen] | ||
131 | return true | ||
132 | } | ||
133 | |||
134 | // LogEntryConfig represents the configuration for binary log entry. | ||
135 | type LogEntryConfig interface { | ||
136 | toProto() *pb.GrpcLogEntry | ||
137 | } | ||
138 | |||
139 | // ClientHeader configs the binary log entry to be a ClientHeader entry. | ||
140 | type ClientHeader struct { | ||
141 | OnClientSide bool | ||
142 | Header metadata.MD | ||
143 | MethodName string | ||
144 | Authority string | ||
145 | Timeout time.Duration | ||
146 | // PeerAddr is required only when it's on server side. | ||
147 | PeerAddr net.Addr | ||
148 | } | ||
149 | |||
150 | func (c *ClientHeader) toProto() *pb.GrpcLogEntry { | ||
151 | // This function doesn't need to set all the fields (e.g. seq ID). The Log | ||
152 | // function will set the fields when necessary. | ||
153 | clientHeader := &pb.ClientHeader{ | ||
154 | Metadata: mdToMetadataProto(c.Header), | ||
155 | MethodName: c.MethodName, | ||
156 | Authority: c.Authority, | ||
157 | } | ||
158 | if c.Timeout > 0 { | ||
159 | clientHeader.Timeout = ptypes.DurationProto(c.Timeout) | ||
160 | } | ||
161 | ret := &pb.GrpcLogEntry{ | ||
162 | Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, | ||
163 | Payload: &pb.GrpcLogEntry_ClientHeader{ | ||
164 | ClientHeader: clientHeader, | ||
165 | }, | ||
166 | } | ||
167 | if c.OnClientSide { | ||
168 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
169 | } else { | ||
170 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
171 | } | ||
172 | if c.PeerAddr != nil { | ||
173 | ret.Peer = addrToProto(c.PeerAddr) | ||
174 | } | ||
175 | return ret | ||
176 | } | ||
177 | |||
178 | // ServerHeader configs the binary log entry to be a ServerHeader entry. | ||
179 | type ServerHeader struct { | ||
180 | OnClientSide bool | ||
181 | Header metadata.MD | ||
182 | // PeerAddr is required only when it's on client side. | ||
183 | PeerAddr net.Addr | ||
184 | } | ||
185 | |||
186 | func (c *ServerHeader) toProto() *pb.GrpcLogEntry { | ||
187 | ret := &pb.GrpcLogEntry{ | ||
188 | Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, | ||
189 | Payload: &pb.GrpcLogEntry_ServerHeader{ | ||
190 | ServerHeader: &pb.ServerHeader{ | ||
191 | Metadata: mdToMetadataProto(c.Header), | ||
192 | }, | ||
193 | }, | ||
194 | } | ||
195 | if c.OnClientSide { | ||
196 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
197 | } else { | ||
198 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
199 | } | ||
200 | if c.PeerAddr != nil { | ||
201 | ret.Peer = addrToProto(c.PeerAddr) | ||
202 | } | ||
203 | return ret | ||
204 | } | ||
205 | |||
206 | // ClientMessage configs the binary log entry to be a ClientMessage entry. | ||
207 | type ClientMessage struct { | ||
208 | OnClientSide bool | ||
209 | // Message can be a proto.Message or []byte. Other messages formats are not | ||
210 | // supported. | ||
211 | Message interface{} | ||
212 | } | ||
213 | |||
214 | func (c *ClientMessage) toProto() *pb.GrpcLogEntry { | ||
215 | var ( | ||
216 | data []byte | ||
217 | err error | ||
218 | ) | ||
219 | if m, ok := c.Message.(proto.Message); ok { | ||
220 | data, err = proto.Marshal(m) | ||
221 | if err != nil { | ||
222 | grpclog.Infof("binarylogging: failed to marshal proto message: %v", err) | ||
223 | } | ||
224 | } else if b, ok := c.Message.([]byte); ok { | ||
225 | data = b | ||
226 | } else { | ||
227 | grpclog.Infof("binarylogging: message to log is neither proto.message nor []byte") | ||
228 | } | ||
229 | ret := &pb.GrpcLogEntry{ | ||
230 | Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, | ||
231 | Payload: &pb.GrpcLogEntry_Message{ | ||
232 | Message: &pb.Message{ | ||
233 | Length: uint32(len(data)), | ||
234 | Data: data, | ||
235 | }, | ||
236 | }, | ||
237 | } | ||
238 | if c.OnClientSide { | ||
239 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
240 | } else { | ||
241 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
242 | } | ||
243 | return ret | ||
244 | } | ||
245 | |||
246 | // ServerMessage configs the binary log entry to be a ServerMessage entry. | ||
247 | type ServerMessage struct { | ||
248 | OnClientSide bool | ||
249 | // Message can be a proto.Message or []byte. Other messages formats are not | ||
250 | // supported. | ||
251 | Message interface{} | ||
252 | } | ||
253 | |||
254 | func (c *ServerMessage) toProto() *pb.GrpcLogEntry { | ||
255 | var ( | ||
256 | data []byte | ||
257 | err error | ||
258 | ) | ||
259 | if m, ok := c.Message.(proto.Message); ok { | ||
260 | data, err = proto.Marshal(m) | ||
261 | if err != nil { | ||
262 | grpclog.Infof("binarylogging: failed to marshal proto message: %v", err) | ||
263 | } | ||
264 | } else if b, ok := c.Message.([]byte); ok { | ||
265 | data = b | ||
266 | } else { | ||
267 | grpclog.Infof("binarylogging: message to log is neither proto.message nor []byte") | ||
268 | } | ||
269 | ret := &pb.GrpcLogEntry{ | ||
270 | Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, | ||
271 | Payload: &pb.GrpcLogEntry_Message{ | ||
272 | Message: &pb.Message{ | ||
273 | Length: uint32(len(data)), | ||
274 | Data: data, | ||
275 | }, | ||
276 | }, | ||
277 | } | ||
278 | if c.OnClientSide { | ||
279 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
280 | } else { | ||
281 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
282 | } | ||
283 | return ret | ||
284 | } | ||
285 | |||
286 | // ClientHalfClose configs the binary log entry to be a ClientHalfClose entry. | ||
287 | type ClientHalfClose struct { | ||
288 | OnClientSide bool | ||
289 | } | ||
290 | |||
291 | func (c *ClientHalfClose) toProto() *pb.GrpcLogEntry { | ||
292 | ret := &pb.GrpcLogEntry{ | ||
293 | Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, | ||
294 | Payload: nil, // No payload here. | ||
295 | } | ||
296 | if c.OnClientSide { | ||
297 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
298 | } else { | ||
299 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
300 | } | ||
301 | return ret | ||
302 | } | ||
303 | |||
304 | // ServerTrailer configs the binary log entry to be a ServerTrailer entry. | ||
305 | type ServerTrailer struct { | ||
306 | OnClientSide bool | ||
307 | Trailer metadata.MD | ||
308 | // Err is the status error. | ||
309 | Err error | ||
310 | // PeerAddr is required only when it's on client side and the RPC is trailer | ||
311 | // only. | ||
312 | PeerAddr net.Addr | ||
313 | } | ||
314 | |||
315 | func (c *ServerTrailer) toProto() *pb.GrpcLogEntry { | ||
316 | st, ok := status.FromError(c.Err) | ||
317 | if !ok { | ||
318 | grpclog.Info("binarylogging: error in trailer is not a status error") | ||
319 | } | ||
320 | var ( | ||
321 | detailsBytes []byte | ||
322 | err error | ||
323 | ) | ||
324 | stProto := st.Proto() | ||
325 | if stProto != nil && len(stProto.Details) != 0 { | ||
326 | detailsBytes, err = proto.Marshal(stProto) | ||
327 | if err != nil { | ||
328 | grpclog.Infof("binarylogging: failed to marshal status proto: %v", err) | ||
329 | } | ||
330 | } | ||
331 | ret := &pb.GrpcLogEntry{ | ||
332 | Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, | ||
333 | Payload: &pb.GrpcLogEntry_Trailer{ | ||
334 | Trailer: &pb.Trailer{ | ||
335 | Metadata: mdToMetadataProto(c.Trailer), | ||
336 | StatusCode: uint32(st.Code()), | ||
337 | StatusMessage: st.Message(), | ||
338 | StatusDetails: detailsBytes, | ||
339 | }, | ||
340 | }, | ||
341 | } | ||
342 | if c.OnClientSide { | ||
343 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
344 | } else { | ||
345 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
346 | } | ||
347 | if c.PeerAddr != nil { | ||
348 | ret.Peer = addrToProto(c.PeerAddr) | ||
349 | } | ||
350 | return ret | ||
351 | } | ||
352 | |||
353 | // Cancel configs the binary log entry to be a Cancel entry. | ||
354 | type Cancel struct { | ||
355 | OnClientSide bool | ||
356 | } | ||
357 | |||
358 | func (c *Cancel) toProto() *pb.GrpcLogEntry { | ||
359 | ret := &pb.GrpcLogEntry{ | ||
360 | Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL, | ||
361 | Payload: nil, | ||
362 | } | ||
363 | if c.OnClientSide { | ||
364 | ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT | ||
365 | } else { | ||
366 | ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER | ||
367 | } | ||
368 | return ret | ||
369 | } | ||
370 | |||
371 | // metadataKeyOmit returns whether the metadata entry with this key should be | ||
372 | // omitted. | ||
373 | func metadataKeyOmit(key string) bool { | ||
374 | switch key { | ||
375 | case "lb-token", ":path", ":authority", "content-encoding", "content-type", "user-agent", "te": | ||
376 | return true | ||
377 | case "grpc-trace-bin": // grpc-trace-bin is special because it's visiable to users. | ||
378 | return false | ||
379 | } | ||
380 | if strings.HasPrefix(key, "grpc-") { | ||
381 | return true | ||
382 | } | ||
383 | return false | ||
384 | } | ||
385 | |||
386 | func mdToMetadataProto(md metadata.MD) *pb.Metadata { | ||
387 | ret := &pb.Metadata{} | ||
388 | for k, vv := range md { | ||
389 | if metadataKeyOmit(k) { | ||
390 | continue | ||
391 | } | ||
392 | for _, v := range vv { | ||
393 | ret.Entry = append(ret.Entry, | ||
394 | &pb.MetadataEntry{ | ||
395 | Key: k, | ||
396 | Value: []byte(v), | ||
397 | }, | ||
398 | ) | ||
399 | } | ||
400 | } | ||
401 | return ret | ||
402 | } | ||
403 | |||
404 | func addrToProto(addr net.Addr) *pb.Address { | ||
405 | ret := &pb.Address{} | ||
406 | switch a := addr.(type) { | ||
407 | case *net.TCPAddr: | ||
408 | if a.IP.To4() != nil { | ||
409 | ret.Type = pb.Address_TYPE_IPV4 | ||
410 | } else if a.IP.To16() != nil { | ||
411 | ret.Type = pb.Address_TYPE_IPV6 | ||
412 | } else { | ||
413 | ret.Type = pb.Address_TYPE_UNKNOWN | ||
414 | // Do not set address and port fields. | ||
415 | break | ||
416 | } | ||
417 | ret.Address = a.IP.String() | ||
418 | ret.IpPort = uint32(a.Port) | ||
419 | case *net.UnixAddr: | ||
420 | ret.Type = pb.Address_TYPE_UNIX | ||
421 | ret.Address = a.String() | ||
422 | default: | ||
423 | ret.Type = pb.Address_TYPE_UNKNOWN | ||
424 | } | ||
425 | return ret | ||
426 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh b/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh new file mode 100644 index 0000000..113d40c --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh | |||
@@ -0,0 +1,33 @@ | |||
1 | #!/bin/bash | ||
2 | # Copyright 2018 gRPC authors. | ||
3 | # | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | # you may not use this file except in compliance with the License. | ||
6 | # You may obtain a copy of the License at | ||
7 | # | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | # | ||
10 | # Unless required by applicable law or agreed to in writing, software | ||
11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | # See the License for the specific language governing permissions and | ||
14 | # limitations under the License. | ||
15 | |||
16 | set -eux -o pipefail | ||
17 | |||
18 | TMP=$(mktemp -d) | ||
19 | |||
20 | function finish { | ||
21 | rm -rf "$TMP" | ||
22 | } | ||
23 | trap finish EXIT | ||
24 | |||
25 | pushd "$TMP" | ||
26 | mkdir -p grpc/binarylog/grpc_binarylog_v1 | ||
27 | curl https://raw.githubusercontent.com/grpc/grpc-proto/master/grpc/binlog/v1/binarylog.proto > grpc/binarylog/grpc_binarylog_v1/binarylog.proto | ||
28 | |||
29 | protoc --go_out=plugins=grpc,paths=source_relative:. -I. grpc/binarylog/grpc_binarylog_v1/*.proto | ||
30 | popd | ||
31 | rm -f ./grpc_binarylog_v1/*.pb.go | ||
32 | cp "$TMP"/grpc/binarylog/grpc_binarylog_v1/*.pb.go ../../binarylog/grpc_binarylog_v1/ | ||
33 | |||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/sink.go b/vendor/google.golang.org/grpc/internal/binarylog/sink.go new file mode 100644 index 0000000..20d044f --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/sink.go | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package binarylog | ||
20 | |||
21 | import ( | ||
22 | "bufio" | ||
23 | "encoding/binary" | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "io/ioutil" | ||
27 | "sync" | ||
28 | "time" | ||
29 | |||
30 | "github.com/golang/protobuf/proto" | ||
31 | pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" | ||
32 | "google.golang.org/grpc/grpclog" | ||
33 | ) | ||
34 | |||
35 | var ( | ||
36 | defaultSink Sink = &noopSink{} // TODO(blog): change this default (file in /tmp). | ||
37 | ) | ||
38 | |||
39 | // SetDefaultSink sets the sink where binary logs will be written to. | ||
40 | // | ||
41 | // Not thread safe. Only set during initialization. | ||
42 | func SetDefaultSink(s Sink) { | ||
43 | if defaultSink != nil { | ||
44 | defaultSink.Close() | ||
45 | } | ||
46 | defaultSink = s | ||
47 | } | ||
48 | |||
49 | // Sink writes log entry into the binary log sink. | ||
50 | type Sink interface { | ||
51 | // Write will be called to write the log entry into the sink. | ||
52 | // | ||
53 | // It should be thread-safe so it can be called in parallel. | ||
54 | Write(*pb.GrpcLogEntry) error | ||
55 | // Close will be called when the Sink is replaced by a new Sink. | ||
56 | Close() error | ||
57 | } | ||
58 | |||
59 | type noopSink struct{} | ||
60 | |||
61 | func (ns *noopSink) Write(*pb.GrpcLogEntry) error { return nil } | ||
62 | func (ns *noopSink) Close() error { return nil } | ||
63 | |||
64 | // newWriterSink creates a binary log sink with the given writer. | ||
65 | // | ||
66 | // Write() marshalls the proto message and writes it to the given writer. Each | ||
67 | // message is prefixed with a 4 byte big endian unsigned integer as the length. | ||
68 | // | ||
69 | // No buffer is done, Close() doesn't try to close the writer. | ||
70 | func newWriterSink(w io.Writer) *writerSink { | ||
71 | return &writerSink{out: w} | ||
72 | } | ||
73 | |||
74 | type writerSink struct { | ||
75 | out io.Writer | ||
76 | } | ||
77 | |||
78 | func (ws *writerSink) Write(e *pb.GrpcLogEntry) error { | ||
79 | b, err := proto.Marshal(e) | ||
80 | if err != nil { | ||
81 | grpclog.Infof("binary logging: failed to marshal proto message: %v", err) | ||
82 | } | ||
83 | hdr := make([]byte, 4) | ||
84 | binary.BigEndian.PutUint32(hdr, uint32(len(b))) | ||
85 | if _, err := ws.out.Write(hdr); err != nil { | ||
86 | return err | ||
87 | } | ||
88 | if _, err := ws.out.Write(b); err != nil { | ||
89 | return err | ||
90 | } | ||
91 | return nil | ||
92 | } | ||
93 | |||
94 | func (ws *writerSink) Close() error { return nil } | ||
95 | |||
96 | type bufWriteCloserSink struct { | ||
97 | mu sync.Mutex | ||
98 | closer io.Closer | ||
99 | out *writerSink // out is built on buf. | ||
100 | buf *bufio.Writer // buf is kept for flush. | ||
101 | |||
102 | writeStartOnce sync.Once | ||
103 | writeTicker *time.Ticker | ||
104 | } | ||
105 | |||
106 | func (fs *bufWriteCloserSink) Write(e *pb.GrpcLogEntry) error { | ||
107 | // Start the write loop when Write is called. | ||
108 | fs.writeStartOnce.Do(fs.startFlushGoroutine) | ||
109 | fs.mu.Lock() | ||
110 | if err := fs.out.Write(e); err != nil { | ||
111 | fs.mu.Unlock() | ||
112 | return err | ||
113 | } | ||
114 | fs.mu.Unlock() | ||
115 | return nil | ||
116 | } | ||
117 | |||
118 | const ( | ||
119 | bufFlushDuration = 60 * time.Second | ||
120 | ) | ||
121 | |||
122 | func (fs *bufWriteCloserSink) startFlushGoroutine() { | ||
123 | fs.writeTicker = time.NewTicker(bufFlushDuration) | ||
124 | go func() { | ||
125 | for range fs.writeTicker.C { | ||
126 | fs.mu.Lock() | ||
127 | fs.buf.Flush() | ||
128 | fs.mu.Unlock() | ||
129 | } | ||
130 | }() | ||
131 | } | ||
132 | |||
133 | func (fs *bufWriteCloserSink) Close() error { | ||
134 | if fs.writeTicker != nil { | ||
135 | fs.writeTicker.Stop() | ||
136 | } | ||
137 | fs.mu.Lock() | ||
138 | fs.buf.Flush() | ||
139 | fs.closer.Close() | ||
140 | fs.out.Close() | ||
141 | fs.mu.Unlock() | ||
142 | return nil | ||
143 | } | ||
144 | |||
145 | func newBufWriteCloserSink(o io.WriteCloser) Sink { | ||
146 | bufW := bufio.NewWriter(o) | ||
147 | return &bufWriteCloserSink{ | ||
148 | closer: o, | ||
149 | out: newWriterSink(bufW), | ||
150 | buf: bufW, | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // NewTempFileSink creates a temp file and returns a Sink that writes to this | ||
155 | // file. | ||
156 | func NewTempFileSink() (Sink, error) { | ||
157 | tempFile, err := ioutil.TempFile("/tmp", "grpcgo_binarylog_*.txt") | ||
158 | if err != nil { | ||
159 | return nil, fmt.Errorf("failed to create temp file: %v", err) | ||
160 | } | ||
161 | return newBufWriteCloserSink(tempFile), nil | ||
162 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/util.go b/vendor/google.golang.org/grpc/internal/binarylog/util.go new file mode 100644 index 0000000..15dc780 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/util.go | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package binarylog | ||
20 | |||
21 | import ( | ||
22 | "errors" | ||
23 | "strings" | ||
24 | ) | ||
25 | |||
26 | // parseMethodName splits service and method from the input. It expects format | ||
27 | // "/service/method". | ||
28 | // | ||
29 | // TODO: move to internal/grpcutil. | ||
30 | func parseMethodName(methodName string) (service, method string, _ error) { | ||
31 | if !strings.HasPrefix(methodName, "/") { | ||
32 | return "", "", errors.New("invalid method name: should start with /") | ||
33 | } | ||
34 | methodName = methodName[1:] | ||
35 | |||
36 | pos := strings.LastIndex(methodName, "/") | ||
37 | if pos < 0 { | ||
38 | return "", "", errors.New("invalid method name: suffix /method is missing") | ||
39 | } | ||
40 | return methodName[:pos], methodName[pos+1:], nil | ||
41 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/channelz/funcs.go b/vendor/google.golang.org/grpc/internal/channelz/funcs.go new file mode 100644 index 0000000..041520d --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/funcs.go | |||
@@ -0,0 +1,699 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package channelz defines APIs for enabling channelz service, entry | ||
20 | // registration/deletion, and accessing channelz data. It also defines channelz | ||
21 | // metric struct formats. | ||
22 | // | ||
23 | // All APIs in this package are experimental. | ||
24 | package channelz | ||
25 | |||
26 | import ( | ||
27 | "sort" | ||
28 | "sync" | ||
29 | "sync/atomic" | ||
30 | "time" | ||
31 | |||
32 | "google.golang.org/grpc/grpclog" | ||
33 | ) | ||
34 | |||
35 | const ( | ||
36 | defaultMaxTraceEntry int32 = 30 | ||
37 | ) | ||
38 | |||
39 | var ( | ||
40 | db dbWrapper | ||
41 | idGen idGenerator | ||
42 | // EntryPerPage defines the number of channelz entries to be shown on a web page. | ||
43 | EntryPerPage = int64(50) | ||
44 | curState int32 | ||
45 | maxTraceEntry = defaultMaxTraceEntry | ||
46 | ) | ||
47 | |||
48 | // TurnOn turns on channelz data collection. | ||
49 | func TurnOn() { | ||
50 | if !IsOn() { | ||
51 | NewChannelzStorage() | ||
52 | atomic.StoreInt32(&curState, 1) | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // IsOn returns whether channelz data collection is on. | ||
57 | func IsOn() bool { | ||
58 | return atomic.CompareAndSwapInt32(&curState, 1, 1) | ||
59 | } | ||
60 | |||
61 | // SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel). | ||
62 | // Setting it to 0 will disable channel tracing. | ||
63 | func SetMaxTraceEntry(i int32) { | ||
64 | atomic.StoreInt32(&maxTraceEntry, i) | ||
65 | } | ||
66 | |||
67 | // ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default. | ||
68 | func ResetMaxTraceEntryToDefault() { | ||
69 | atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry) | ||
70 | } | ||
71 | |||
72 | func getMaxTraceEntry() int { | ||
73 | i := atomic.LoadInt32(&maxTraceEntry) | ||
74 | return int(i) | ||
75 | } | ||
76 | |||
77 | // dbWarpper wraps around a reference to internal channelz data storage, and | ||
78 | // provide synchronized functionality to set and get the reference. | ||
79 | type dbWrapper struct { | ||
80 | mu sync.RWMutex | ||
81 | DB *channelMap | ||
82 | } | ||
83 | |||
84 | func (d *dbWrapper) set(db *channelMap) { | ||
85 | d.mu.Lock() | ||
86 | d.DB = db | ||
87 | d.mu.Unlock() | ||
88 | } | ||
89 | |||
90 | func (d *dbWrapper) get() *channelMap { | ||
91 | d.mu.RLock() | ||
92 | defer d.mu.RUnlock() | ||
93 | return d.DB | ||
94 | } | ||
95 | |||
96 | // NewChannelzStorage initializes channelz data storage and id generator. | ||
97 | // | ||
98 | // Note: This function is exported for testing purpose only. User should not call | ||
99 | // it in most cases. | ||
100 | func NewChannelzStorage() { | ||
101 | db.set(&channelMap{ | ||
102 | topLevelChannels: make(map[int64]struct{}), | ||
103 | channels: make(map[int64]*channel), | ||
104 | listenSockets: make(map[int64]*listenSocket), | ||
105 | normalSockets: make(map[int64]*normalSocket), | ||
106 | servers: make(map[int64]*server), | ||
107 | subChannels: make(map[int64]*subChannel), | ||
108 | }) | ||
109 | idGen.reset() | ||
110 | } | ||
111 | |||
112 | // GetTopChannels returns a slice of top channel's ChannelMetric, along with a | ||
113 | // boolean indicating whether there's more top channels to be queried for. | ||
114 | // | ||
115 | // The arg id specifies that only top channel with id at or above it will be included | ||
116 | // in the result. The returned slice is up to a length of the arg maxResults or | ||
117 | // EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||
118 | func GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) { | ||
119 | return db.get().GetTopChannels(id, maxResults) | ||
120 | } | ||
121 | |||
122 | // GetServers returns a slice of server's ServerMetric, along with a | ||
123 | // boolean indicating whether there's more servers to be queried for. | ||
124 | // | ||
125 | // The arg id specifies that only server with id at or above it will be included | ||
126 | // in the result. The returned slice is up to a length of the arg maxResults or | ||
127 | // EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||
128 | func GetServers(id int64, maxResults int64) ([]*ServerMetric, bool) { | ||
129 | return db.get().GetServers(id, maxResults) | ||
130 | } | ||
131 | |||
132 | // GetServerSockets returns a slice of server's (identified by id) normal socket's | ||
133 | // SocketMetric, along with a boolean indicating whether there's more sockets to | ||
134 | // be queried for. | ||
135 | // | ||
136 | // The arg startID specifies that only sockets with id at or above it will be | ||
137 | // included in the result. The returned slice is up to a length of the arg maxResults | ||
138 | // or EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||
139 | func GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) { | ||
140 | return db.get().GetServerSockets(id, startID, maxResults) | ||
141 | } | ||
142 | |||
143 | // GetChannel returns the ChannelMetric for the channel (identified by id). | ||
144 | func GetChannel(id int64) *ChannelMetric { | ||
145 | return db.get().GetChannel(id) | ||
146 | } | ||
147 | |||
148 | // GetSubChannel returns the SubChannelMetric for the subchannel (identified by id). | ||
149 | func GetSubChannel(id int64) *SubChannelMetric { | ||
150 | return db.get().GetSubChannel(id) | ||
151 | } | ||
152 | |||
153 | // GetSocket returns the SocketInternalMetric for the socket (identified by id). | ||
154 | func GetSocket(id int64) *SocketMetric { | ||
155 | return db.get().GetSocket(id) | ||
156 | } | ||
157 | |||
158 | // GetServer returns the ServerMetric for the server (identified by id). | ||
159 | func GetServer(id int64) *ServerMetric { | ||
160 | return db.get().GetServer(id) | ||
161 | } | ||
162 | |||
163 | // RegisterChannel registers the given channel c in channelz database with ref | ||
164 | // as its reference name, and add it to the child list of its parent (identified | ||
165 | // by pid). pid = 0 means no parent. It returns the unique channelz tracking id | ||
166 | // assigned to this channel. | ||
167 | func RegisterChannel(c Channel, pid int64, ref string) int64 { | ||
168 | id := idGen.genID() | ||
169 | cn := &channel{ | ||
170 | refName: ref, | ||
171 | c: c, | ||
172 | subChans: make(map[int64]string), | ||
173 | nestedChans: make(map[int64]string), | ||
174 | id: id, | ||
175 | pid: pid, | ||
176 | trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, | ||
177 | } | ||
178 | if pid == 0 { | ||
179 | db.get().addChannel(id, cn, true, pid, ref) | ||
180 | } else { | ||
181 | db.get().addChannel(id, cn, false, pid, ref) | ||
182 | } | ||
183 | return id | ||
184 | } | ||
185 | |||
186 | // RegisterSubChannel registers the given channel c in channelz database with ref | ||
187 | // as its reference name, and add it to the child list of its parent (identified | ||
188 | // by pid). It returns the unique channelz tracking id assigned to this subchannel. | ||
189 | func RegisterSubChannel(c Channel, pid int64, ref string) int64 { | ||
190 | if pid == 0 { | ||
191 | grpclog.Error("a SubChannel's parent id cannot be 0") | ||
192 | return 0 | ||
193 | } | ||
194 | id := idGen.genID() | ||
195 | sc := &subChannel{ | ||
196 | refName: ref, | ||
197 | c: c, | ||
198 | sockets: make(map[int64]string), | ||
199 | id: id, | ||
200 | pid: pid, | ||
201 | trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, | ||
202 | } | ||
203 | db.get().addSubChannel(id, sc, pid, ref) | ||
204 | return id | ||
205 | } | ||
206 | |||
207 | // RegisterServer registers the given server s in channelz database. It returns | ||
208 | // the unique channelz tracking id assigned to this server. | ||
209 | func RegisterServer(s Server, ref string) int64 { | ||
210 | id := idGen.genID() | ||
211 | svr := &server{ | ||
212 | refName: ref, | ||
213 | s: s, | ||
214 | sockets: make(map[int64]string), | ||
215 | listenSockets: make(map[int64]string), | ||
216 | id: id, | ||
217 | } | ||
218 | db.get().addServer(id, svr) | ||
219 | return id | ||
220 | } | ||
221 | |||
222 | // RegisterListenSocket registers the given listen socket s in channelz database | ||
223 | // with ref as its reference name, and add it to the child list of its parent | ||
224 | // (identified by pid). It returns the unique channelz tracking id assigned to | ||
225 | // this listen socket. | ||
226 | func RegisterListenSocket(s Socket, pid int64, ref string) int64 { | ||
227 | if pid == 0 { | ||
228 | grpclog.Error("a ListenSocket's parent id cannot be 0") | ||
229 | return 0 | ||
230 | } | ||
231 | id := idGen.genID() | ||
232 | ls := &listenSocket{refName: ref, s: s, id: id, pid: pid} | ||
233 | db.get().addListenSocket(id, ls, pid, ref) | ||
234 | return id | ||
235 | } | ||
236 | |||
237 | // RegisterNormalSocket registers the given normal socket s in channelz database | ||
238 | // with ref as its reference name, and add it to the child list of its parent | ||
239 | // (identified by pid). It returns the unique channelz tracking id assigned to | ||
240 | // this normal socket. | ||
241 | func RegisterNormalSocket(s Socket, pid int64, ref string) int64 { | ||
242 | if pid == 0 { | ||
243 | grpclog.Error("a NormalSocket's parent id cannot be 0") | ||
244 | return 0 | ||
245 | } | ||
246 | id := idGen.genID() | ||
247 | ns := &normalSocket{refName: ref, s: s, id: id, pid: pid} | ||
248 | db.get().addNormalSocket(id, ns, pid, ref) | ||
249 | return id | ||
250 | } | ||
251 | |||
252 | // RemoveEntry removes an entry with unique channelz trakcing id to be id from | ||
253 | // channelz database. | ||
254 | func RemoveEntry(id int64) { | ||
255 | db.get().removeEntry(id) | ||
256 | } | ||
257 | |||
258 | // TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added | ||
259 | // to the channel trace. | ||
260 | // The Parent field is optional. It is used for event that will be recorded in the entity's parent | ||
261 | // trace also. | ||
262 | type TraceEventDesc struct { | ||
263 | Desc string | ||
264 | Severity Severity | ||
265 | Parent *TraceEventDesc | ||
266 | } | ||
267 | |||
268 | // AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc. | ||
269 | func AddTraceEvent(id int64, desc *TraceEventDesc) { | ||
270 | if getMaxTraceEntry() == 0 { | ||
271 | return | ||
272 | } | ||
273 | db.get().traceEvent(id, desc) | ||
274 | } | ||
275 | |||
276 | // channelMap is the storage data structure for channelz. | ||
277 | // Methods of channelMap can be divided in two two categories with respect to locking. | ||
278 | // 1. Methods acquire the global lock. | ||
279 | // 2. Methods that can only be called when global lock is held. | ||
280 | // A second type of method need always to be called inside a first type of method. | ||
281 | type channelMap struct { | ||
282 | mu sync.RWMutex | ||
283 | topLevelChannels map[int64]struct{} | ||
284 | servers map[int64]*server | ||
285 | channels map[int64]*channel | ||
286 | subChannels map[int64]*subChannel | ||
287 | listenSockets map[int64]*listenSocket | ||
288 | normalSockets map[int64]*normalSocket | ||
289 | } | ||
290 | |||
291 | func (c *channelMap) addServer(id int64, s *server) { | ||
292 | c.mu.Lock() | ||
293 | s.cm = c | ||
294 | c.servers[id] = s | ||
295 | c.mu.Unlock() | ||
296 | } | ||
297 | |||
298 | func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) { | ||
299 | c.mu.Lock() | ||
300 | cn.cm = c | ||
301 | cn.trace.cm = c | ||
302 | c.channels[id] = cn | ||
303 | if isTopChannel { | ||
304 | c.topLevelChannels[id] = struct{}{} | ||
305 | } else { | ||
306 | c.findEntry(pid).addChild(id, cn) | ||
307 | } | ||
308 | c.mu.Unlock() | ||
309 | } | ||
310 | |||
311 | func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) { | ||
312 | c.mu.Lock() | ||
313 | sc.cm = c | ||
314 | sc.trace.cm = c | ||
315 | c.subChannels[id] = sc | ||
316 | c.findEntry(pid).addChild(id, sc) | ||
317 | c.mu.Unlock() | ||
318 | } | ||
319 | |||
320 | func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64, ref string) { | ||
321 | c.mu.Lock() | ||
322 | ls.cm = c | ||
323 | c.listenSockets[id] = ls | ||
324 | c.findEntry(pid).addChild(id, ls) | ||
325 | c.mu.Unlock() | ||
326 | } | ||
327 | |||
328 | func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref string) { | ||
329 | c.mu.Lock() | ||
330 | ns.cm = c | ||
331 | c.normalSockets[id] = ns | ||
332 | c.findEntry(pid).addChild(id, ns) | ||
333 | c.mu.Unlock() | ||
334 | } | ||
335 | |||
336 | // removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to | ||
337 | // wait on the deletion of its children and until no other entity's channel trace references it. | ||
338 | // It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully | ||
339 | // shutting down server will lead to the server being also deleted. | ||
340 | func (c *channelMap) removeEntry(id int64) { | ||
341 | c.mu.Lock() | ||
342 | c.findEntry(id).triggerDelete() | ||
343 | c.mu.Unlock() | ||
344 | } | ||
345 | |||
346 | // c.mu must be held by the caller | ||
347 | func (c *channelMap) decrTraceRefCount(id int64) { | ||
348 | e := c.findEntry(id) | ||
349 | if v, ok := e.(tracedChannel); ok { | ||
350 | v.decrTraceRefCount() | ||
351 | e.deleteSelfIfReady() | ||
352 | } | ||
353 | } | ||
354 | |||
355 | // c.mu must be held by the caller. | ||
356 | func (c *channelMap) findEntry(id int64) entry { | ||
357 | var v entry | ||
358 | var ok bool | ||
359 | if v, ok = c.channels[id]; ok { | ||
360 | return v | ||
361 | } | ||
362 | if v, ok = c.subChannels[id]; ok { | ||
363 | return v | ||
364 | } | ||
365 | if v, ok = c.servers[id]; ok { | ||
366 | return v | ||
367 | } | ||
368 | if v, ok = c.listenSockets[id]; ok { | ||
369 | return v | ||
370 | } | ||
371 | if v, ok = c.normalSockets[id]; ok { | ||
372 | return v | ||
373 | } | ||
374 | return &dummyEntry{idNotFound: id} | ||
375 | } | ||
376 | |||
377 | // c.mu must be held by the caller | ||
378 | // deleteEntry simply deletes an entry from the channelMap. Before calling this | ||
379 | // method, caller must check this entry is ready to be deleted, i.e removeEntry() | ||
380 | // has been called on it, and no children still exist. | ||
381 | // Conditionals are ordered by the expected frequency of deletion of each entity | ||
382 | // type, in order to optimize performance. | ||
383 | func (c *channelMap) deleteEntry(id int64) { | ||
384 | var ok bool | ||
385 | if _, ok = c.normalSockets[id]; ok { | ||
386 | delete(c.normalSockets, id) | ||
387 | return | ||
388 | } | ||
389 | if _, ok = c.subChannels[id]; ok { | ||
390 | delete(c.subChannels, id) | ||
391 | return | ||
392 | } | ||
393 | if _, ok = c.channels[id]; ok { | ||
394 | delete(c.channels, id) | ||
395 | delete(c.topLevelChannels, id) | ||
396 | return | ||
397 | } | ||
398 | if _, ok = c.listenSockets[id]; ok { | ||
399 | delete(c.listenSockets, id) | ||
400 | return | ||
401 | } | ||
402 | if _, ok = c.servers[id]; ok { | ||
403 | delete(c.servers, id) | ||
404 | return | ||
405 | } | ||
406 | } | ||
407 | |||
408 | func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) { | ||
409 | c.mu.Lock() | ||
410 | child := c.findEntry(id) | ||
411 | childTC, ok := child.(tracedChannel) | ||
412 | if !ok { | ||
413 | c.mu.Unlock() | ||
414 | return | ||
415 | } | ||
416 | childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()}) | ||
417 | if desc.Parent != nil { | ||
418 | parent := c.findEntry(child.getParentID()) | ||
419 | var chanType RefChannelType | ||
420 | switch child.(type) { | ||
421 | case *channel: | ||
422 | chanType = RefChannel | ||
423 | case *subChannel: | ||
424 | chanType = RefSubChannel | ||
425 | } | ||
426 | if parentTC, ok := parent.(tracedChannel); ok { | ||
427 | parentTC.getChannelTrace().append(&TraceEvent{ | ||
428 | Desc: desc.Parent.Desc, | ||
429 | Severity: desc.Parent.Severity, | ||
430 | Timestamp: time.Now(), | ||
431 | RefID: id, | ||
432 | RefName: childTC.getRefName(), | ||
433 | RefType: chanType, | ||
434 | }) | ||
435 | childTC.incrTraceRefCount() | ||
436 | } | ||
437 | } | ||
438 | c.mu.Unlock() | ||
439 | } | ||
440 | |||
441 | type int64Slice []int64 | ||
442 | |||
443 | func (s int64Slice) Len() int { return len(s) } | ||
444 | func (s int64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
445 | func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] } | ||
446 | |||
447 | func copyMap(m map[int64]string) map[int64]string { | ||
448 | n := make(map[int64]string) | ||
449 | for k, v := range m { | ||
450 | n[k] = v | ||
451 | } | ||
452 | return n | ||
453 | } | ||
454 | |||
455 | func min(a, b int64) int64 { | ||
456 | if a < b { | ||
457 | return a | ||
458 | } | ||
459 | return b | ||
460 | } | ||
461 | |||
462 | func (c *channelMap) GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) { | ||
463 | if maxResults <= 0 { | ||
464 | maxResults = EntryPerPage | ||
465 | } | ||
466 | c.mu.RLock() | ||
467 | l := int64(len(c.topLevelChannels)) | ||
468 | ids := make([]int64, 0, l) | ||
469 | cns := make([]*channel, 0, min(l, maxResults)) | ||
470 | |||
471 | for k := range c.topLevelChannels { | ||
472 | ids = append(ids, k) | ||
473 | } | ||
474 | sort.Sort(int64Slice(ids)) | ||
475 | idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id }) | ||
476 | count := int64(0) | ||
477 | var end bool | ||
478 | var t []*ChannelMetric | ||
479 | for i, v := range ids[idx:] { | ||
480 | if count == maxResults { | ||
481 | break | ||
482 | } | ||
483 | if cn, ok := c.channels[v]; ok { | ||
484 | cns = append(cns, cn) | ||
485 | t = append(t, &ChannelMetric{ | ||
486 | NestedChans: copyMap(cn.nestedChans), | ||
487 | SubChans: copyMap(cn.subChans), | ||
488 | }) | ||
489 | count++ | ||
490 | } | ||
491 | if i == len(ids[idx:])-1 { | ||
492 | end = true | ||
493 | break | ||
494 | } | ||
495 | } | ||
496 | c.mu.RUnlock() | ||
497 | if count == 0 { | ||
498 | end = true | ||
499 | } | ||
500 | |||
501 | for i, cn := range cns { | ||
502 | t[i].ChannelData = cn.c.ChannelzMetric() | ||
503 | t[i].ID = cn.id | ||
504 | t[i].RefName = cn.refName | ||
505 | t[i].Trace = cn.trace.dumpData() | ||
506 | } | ||
507 | return t, end | ||
508 | } | ||
509 | |||
510 | func (c *channelMap) GetServers(id, maxResults int64) ([]*ServerMetric, bool) { | ||
511 | if maxResults <= 0 { | ||
512 | maxResults = EntryPerPage | ||
513 | } | ||
514 | c.mu.RLock() | ||
515 | l := int64(len(c.servers)) | ||
516 | ids := make([]int64, 0, l) | ||
517 | ss := make([]*server, 0, min(l, maxResults)) | ||
518 | for k := range c.servers { | ||
519 | ids = append(ids, k) | ||
520 | } | ||
521 | sort.Sort(int64Slice(ids)) | ||
522 | idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id }) | ||
523 | count := int64(0) | ||
524 | var end bool | ||
525 | var s []*ServerMetric | ||
526 | for i, v := range ids[idx:] { | ||
527 | if count == maxResults { | ||
528 | break | ||
529 | } | ||
530 | if svr, ok := c.servers[v]; ok { | ||
531 | ss = append(ss, svr) | ||
532 | s = append(s, &ServerMetric{ | ||
533 | ListenSockets: copyMap(svr.listenSockets), | ||
534 | }) | ||
535 | count++ | ||
536 | } | ||
537 | if i == len(ids[idx:])-1 { | ||
538 | end = true | ||
539 | break | ||
540 | } | ||
541 | } | ||
542 | c.mu.RUnlock() | ||
543 | if count == 0 { | ||
544 | end = true | ||
545 | } | ||
546 | |||
547 | for i, svr := range ss { | ||
548 | s[i].ServerData = svr.s.ChannelzMetric() | ||
549 | s[i].ID = svr.id | ||
550 | s[i].RefName = svr.refName | ||
551 | } | ||
552 | return s, end | ||
553 | } | ||
554 | |||
555 | func (c *channelMap) GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) { | ||
556 | if maxResults <= 0 { | ||
557 | maxResults = EntryPerPage | ||
558 | } | ||
559 | var svr *server | ||
560 | var ok bool | ||
561 | c.mu.RLock() | ||
562 | if svr, ok = c.servers[id]; !ok { | ||
563 | // server with id doesn't exist. | ||
564 | c.mu.RUnlock() | ||
565 | return nil, true | ||
566 | } | ||
567 | svrskts := svr.sockets | ||
568 | l := int64(len(svrskts)) | ||
569 | ids := make([]int64, 0, l) | ||
570 | sks := make([]*normalSocket, 0, min(l, maxResults)) | ||
571 | for k := range svrskts { | ||
572 | ids = append(ids, k) | ||
573 | } | ||
574 | sort.Sort(int64Slice(ids)) | ||
575 | idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= startID }) | ||
576 | count := int64(0) | ||
577 | var end bool | ||
578 | for i, v := range ids[idx:] { | ||
579 | if count == maxResults { | ||
580 | break | ||
581 | } | ||
582 | if ns, ok := c.normalSockets[v]; ok { | ||
583 | sks = append(sks, ns) | ||
584 | count++ | ||
585 | } | ||
586 | if i == len(ids[idx:])-1 { | ||
587 | end = true | ||
588 | break | ||
589 | } | ||
590 | } | ||
591 | c.mu.RUnlock() | ||
592 | if count == 0 { | ||
593 | end = true | ||
594 | } | ||
595 | var s []*SocketMetric | ||
596 | for _, ns := range sks { | ||
597 | sm := &SocketMetric{} | ||
598 | sm.SocketData = ns.s.ChannelzMetric() | ||
599 | sm.ID = ns.id | ||
600 | sm.RefName = ns.refName | ||
601 | s = append(s, sm) | ||
602 | } | ||
603 | return s, end | ||
604 | } | ||
605 | |||
606 | func (c *channelMap) GetChannel(id int64) *ChannelMetric { | ||
607 | cm := &ChannelMetric{} | ||
608 | var cn *channel | ||
609 | var ok bool | ||
610 | c.mu.RLock() | ||
611 | if cn, ok = c.channels[id]; !ok { | ||
612 | // channel with id doesn't exist. | ||
613 | c.mu.RUnlock() | ||
614 | return nil | ||
615 | } | ||
616 | cm.NestedChans = copyMap(cn.nestedChans) | ||
617 | cm.SubChans = copyMap(cn.subChans) | ||
618 | // cn.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of cn.c when | ||
619 | // holding the lock to prevent potential data race. | ||
620 | chanCopy := cn.c | ||
621 | c.mu.RUnlock() | ||
622 | cm.ChannelData = chanCopy.ChannelzMetric() | ||
623 | cm.ID = cn.id | ||
624 | cm.RefName = cn.refName | ||
625 | cm.Trace = cn.trace.dumpData() | ||
626 | return cm | ||
627 | } | ||
628 | |||
629 | func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric { | ||
630 | cm := &SubChannelMetric{} | ||
631 | var sc *subChannel | ||
632 | var ok bool | ||
633 | c.mu.RLock() | ||
634 | if sc, ok = c.subChannels[id]; !ok { | ||
635 | // subchannel with id doesn't exist. | ||
636 | c.mu.RUnlock() | ||
637 | return nil | ||
638 | } | ||
639 | cm.Sockets = copyMap(sc.sockets) | ||
640 | // sc.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of sc.c when | ||
641 | // holding the lock to prevent potential data race. | ||
642 | chanCopy := sc.c | ||
643 | c.mu.RUnlock() | ||
644 | cm.ChannelData = chanCopy.ChannelzMetric() | ||
645 | cm.ID = sc.id | ||
646 | cm.RefName = sc.refName | ||
647 | cm.Trace = sc.trace.dumpData() | ||
648 | return cm | ||
649 | } | ||
650 | |||
651 | func (c *channelMap) GetSocket(id int64) *SocketMetric { | ||
652 | sm := &SocketMetric{} | ||
653 | c.mu.RLock() | ||
654 | if ls, ok := c.listenSockets[id]; ok { | ||
655 | c.mu.RUnlock() | ||
656 | sm.SocketData = ls.s.ChannelzMetric() | ||
657 | sm.ID = ls.id | ||
658 | sm.RefName = ls.refName | ||
659 | return sm | ||
660 | } | ||
661 | if ns, ok := c.normalSockets[id]; ok { | ||
662 | c.mu.RUnlock() | ||
663 | sm.SocketData = ns.s.ChannelzMetric() | ||
664 | sm.ID = ns.id | ||
665 | sm.RefName = ns.refName | ||
666 | return sm | ||
667 | } | ||
668 | c.mu.RUnlock() | ||
669 | return nil | ||
670 | } | ||
671 | |||
672 | func (c *channelMap) GetServer(id int64) *ServerMetric { | ||
673 | sm := &ServerMetric{} | ||
674 | var svr *server | ||
675 | var ok bool | ||
676 | c.mu.RLock() | ||
677 | if svr, ok = c.servers[id]; !ok { | ||
678 | c.mu.RUnlock() | ||
679 | return nil | ||
680 | } | ||
681 | sm.ListenSockets = copyMap(svr.listenSockets) | ||
682 | c.mu.RUnlock() | ||
683 | sm.ID = svr.id | ||
684 | sm.RefName = svr.refName | ||
685 | sm.ServerData = svr.s.ChannelzMetric() | ||
686 | return sm | ||
687 | } | ||
688 | |||
689 | type idGenerator struct { | ||
690 | id int64 | ||
691 | } | ||
692 | |||
693 | func (i *idGenerator) reset() { | ||
694 | atomic.StoreInt64(&i.id, 0) | ||
695 | } | ||
696 | |||
697 | func (i *idGenerator) genID() int64 { | ||
698 | return atomic.AddInt64(&i.id, 1) | ||
699 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/channelz/types.go b/vendor/google.golang.org/grpc/internal/channelz/types.go new file mode 100644 index 0000000..17c2274 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/types.go | |||
@@ -0,0 +1,702 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package channelz | ||
20 | |||
21 | import ( | ||
22 | "net" | ||
23 | "sync" | ||
24 | "sync/atomic" | ||
25 | "time" | ||
26 | |||
27 | "google.golang.org/grpc/connectivity" | ||
28 | "google.golang.org/grpc/credentials" | ||
29 | "google.golang.org/grpc/grpclog" | ||
30 | ) | ||
31 | |||
32 | // entry represents a node in the channelz database. | ||
33 | type entry interface { | ||
34 | // addChild adds a child e, whose channelz id is id to child list | ||
35 | addChild(id int64, e entry) | ||
36 | // deleteChild deletes a child with channelz id to be id from child list | ||
37 | deleteChild(id int64) | ||
38 | // triggerDelete tries to delete self from channelz database. However, if child | ||
39 | // list is not empty, then deletion from the database is on hold until the last | ||
40 | // child is deleted from database. | ||
41 | triggerDelete() | ||
42 | // deleteSelfIfReady check whether triggerDelete() has been called before, and whether child | ||
43 | // list is now empty. If both conditions are met, then delete self from database. | ||
44 | deleteSelfIfReady() | ||
45 | // getParentID returns parent ID of the entry. 0 value parent ID means no parent. | ||
46 | getParentID() int64 | ||
47 | } | ||
48 | |||
49 | // dummyEntry is a fake entry to handle entry not found case. | ||
50 | type dummyEntry struct { | ||
51 | idNotFound int64 | ||
52 | } | ||
53 | |||
54 | func (d *dummyEntry) addChild(id int64, e entry) { | ||
55 | // Note: It is possible for a normal program to reach here under race condition. | ||
56 | // For example, there could be a race between ClientConn.Close() info being propagated | ||
57 | // to addrConn and http2Client. ClientConn.Close() cancel the context and result | ||
58 | // in http2Client to error. The error info is then caught by transport monitor | ||
59 | // and before addrConn.tearDown() is called in side ClientConn.Close(). Therefore, | ||
60 | // the addrConn will create a new transport. And when registering the new transport in | ||
61 | // channelz, its parent addrConn could have already been torn down and deleted | ||
62 | // from channelz tracking, and thus reach the code here. | ||
63 | grpclog.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", e, id, d.idNotFound) | ||
64 | } | ||
65 | |||
66 | func (d *dummyEntry) deleteChild(id int64) { | ||
67 | // It is possible for a normal program to reach here under race condition. | ||
68 | // Refer to the example described in addChild(). | ||
69 | grpclog.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", id, d.idNotFound) | ||
70 | } | ||
71 | |||
72 | func (d *dummyEntry) triggerDelete() { | ||
73 | grpclog.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", d.idNotFound) | ||
74 | } | ||
75 | |||
76 | func (*dummyEntry) deleteSelfIfReady() { | ||
77 | // code should not reach here. deleteSelfIfReady is always called on an existing entry. | ||
78 | } | ||
79 | |||
80 | func (*dummyEntry) getParentID() int64 { | ||
81 | return 0 | ||
82 | } | ||
83 | |||
84 | // ChannelMetric defines the info channelz provides for a specific Channel, which | ||
85 | // includes ChannelInternalMetric and channelz-specific data, such as channelz id, | ||
86 | // child list, etc. | ||
87 | type ChannelMetric struct { | ||
88 | // ID is the channelz id of this channel. | ||
89 | ID int64 | ||
90 | // RefName is the human readable reference string of this channel. | ||
91 | RefName string | ||
92 | // ChannelData contains channel internal metric reported by the channel through | ||
93 | // ChannelzMetric(). | ||
94 | ChannelData *ChannelInternalMetric | ||
95 | // NestedChans tracks the nested channel type children of this channel in the format of | ||
96 | // a map from nested channel channelz id to corresponding reference string. | ||
97 | NestedChans map[int64]string | ||
98 | // SubChans tracks the subchannel type children of this channel in the format of a | ||
99 | // map from subchannel channelz id to corresponding reference string. | ||
100 | SubChans map[int64]string | ||
101 | // Sockets tracks the socket type children of this channel in the format of a map | ||
102 | // from socket channelz id to corresponding reference string. | ||
103 | // Note current grpc implementation doesn't allow channel having sockets directly, | ||
104 | // therefore, this is field is unused. | ||
105 | Sockets map[int64]string | ||
106 | // Trace contains the most recent traced events. | ||
107 | Trace *ChannelTrace | ||
108 | } | ||
109 | |||
110 | // SubChannelMetric defines the info channelz provides for a specific SubChannel, | ||
111 | // which includes ChannelInternalMetric and channelz-specific data, such as | ||
112 | // channelz id, child list, etc. | ||
113 | type SubChannelMetric struct { | ||
114 | // ID is the channelz id of this subchannel. | ||
115 | ID int64 | ||
116 | // RefName is the human readable reference string of this subchannel. | ||
117 | RefName string | ||
118 | // ChannelData contains subchannel internal metric reported by the subchannel | ||
119 | // through ChannelzMetric(). | ||
120 | ChannelData *ChannelInternalMetric | ||
121 | // NestedChans tracks the nested channel type children of this subchannel in the format of | ||
122 | // a map from nested channel channelz id to corresponding reference string. | ||
123 | // Note current grpc implementation doesn't allow subchannel to have nested channels | ||
124 | // as children, therefore, this field is unused. | ||
125 | NestedChans map[int64]string | ||
126 | // SubChans tracks the subchannel type children of this subchannel in the format of a | ||
127 | // map from subchannel channelz id to corresponding reference string. | ||
128 | // Note current grpc implementation doesn't allow subchannel to have subchannels | ||
129 | // as children, therefore, this field is unused. | ||
130 | SubChans map[int64]string | ||
131 | // Sockets tracks the socket type children of this subchannel in the format of a map | ||
132 | // from socket channelz id to corresponding reference string. | ||
133 | Sockets map[int64]string | ||
134 | // Trace contains the most recent traced events. | ||
135 | Trace *ChannelTrace | ||
136 | } | ||
137 | |||
138 | // ChannelInternalMetric defines the struct that the implementor of Channel interface | ||
139 | // should return from ChannelzMetric(). | ||
140 | type ChannelInternalMetric struct { | ||
141 | // current connectivity state of the channel. | ||
142 | State connectivity.State | ||
143 | // The target this channel originally tried to connect to. May be absent | ||
144 | Target string | ||
145 | // The number of calls started on the channel. | ||
146 | CallsStarted int64 | ||
147 | // The number of calls that have completed with an OK status. | ||
148 | CallsSucceeded int64 | ||
149 | // The number of calls that have a completed with a non-OK status. | ||
150 | CallsFailed int64 | ||
151 | // The last time a call was started on the channel. | ||
152 | LastCallStartedTimestamp time.Time | ||
153 | } | ||
154 | |||
155 | // ChannelTrace stores traced events on a channel/subchannel and related info. | ||
156 | type ChannelTrace struct { | ||
157 | // EventNum is the number of events that ever got traced (i.e. including those that have been deleted) | ||
158 | EventNum int64 | ||
159 | // CreationTime is the creation time of the trace. | ||
160 | CreationTime time.Time | ||
161 | // Events stores the most recent trace events (up to $maxTraceEntry, newer event will overwrite the | ||
162 | // oldest one) | ||
163 | Events []*TraceEvent | ||
164 | } | ||
165 | |||
166 | // TraceEvent represent a single trace event | ||
167 | type TraceEvent struct { | ||
168 | // Desc is a simple description of the trace event. | ||
169 | Desc string | ||
170 | // Severity states the severity of this trace event. | ||
171 | Severity Severity | ||
172 | // Timestamp is the event time. | ||
173 | Timestamp time.Time | ||
174 | // RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is | ||
175 | // involved in this event. | ||
176 | // e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside []) | ||
177 | RefID int64 | ||
178 | // RefName is the reference name for the entity that gets referenced in the event. | ||
179 | RefName string | ||
180 | // RefType indicates the referenced entity type, i.e Channel or SubChannel. | ||
181 | RefType RefChannelType | ||
182 | } | ||
183 | |||
184 | // Channel is the interface that should be satisfied in order to be tracked by | ||
185 | // channelz as Channel or SubChannel. | ||
186 | type Channel interface { | ||
187 | ChannelzMetric() *ChannelInternalMetric | ||
188 | } | ||
189 | |||
190 | type dummyChannel struct{} | ||
191 | |||
192 | func (d *dummyChannel) ChannelzMetric() *ChannelInternalMetric { | ||
193 | return &ChannelInternalMetric{} | ||
194 | } | ||
195 | |||
196 | type channel struct { | ||
197 | refName string | ||
198 | c Channel | ||
199 | closeCalled bool | ||
200 | nestedChans map[int64]string | ||
201 | subChans map[int64]string | ||
202 | id int64 | ||
203 | pid int64 | ||
204 | cm *channelMap | ||
205 | trace *channelTrace | ||
206 | // traceRefCount is the number of trace events that reference this channel. | ||
207 | // Non-zero traceRefCount means the trace of this channel cannot be deleted. | ||
208 | traceRefCount int32 | ||
209 | } | ||
210 | |||
211 | func (c *channel) addChild(id int64, e entry) { | ||
212 | switch v := e.(type) { | ||
213 | case *subChannel: | ||
214 | c.subChans[id] = v.refName | ||
215 | case *channel: | ||
216 | c.nestedChans[id] = v.refName | ||
217 | default: | ||
218 | grpclog.Errorf("cannot add a child (id = %d) of type %T to a channel", id, e) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | func (c *channel) deleteChild(id int64) { | ||
223 | delete(c.subChans, id) | ||
224 | delete(c.nestedChans, id) | ||
225 | c.deleteSelfIfReady() | ||
226 | } | ||
227 | |||
228 | func (c *channel) triggerDelete() { | ||
229 | c.closeCalled = true | ||
230 | c.deleteSelfIfReady() | ||
231 | } | ||
232 | |||
233 | func (c *channel) getParentID() int64 { | ||
234 | return c.pid | ||
235 | } | ||
236 | |||
237 | // deleteSelfFromTree tries to delete the channel from the channelz entry relation tree, which means | ||
238 | // deleting the channel reference from its parent's child list. | ||
239 | // | ||
240 | // In order for a channel to be deleted from the tree, it must meet the criteria that, removal of the | ||
241 | // corresponding grpc object has been invoked, and the channel does not have any children left. | ||
242 | // | ||
243 | // The returned boolean value indicates whether the channel has been successfully deleted from tree. | ||
244 | func (c *channel) deleteSelfFromTree() (deleted bool) { | ||
245 | if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 { | ||
246 | return false | ||
247 | } | ||
248 | // not top channel | ||
249 | if c.pid != 0 { | ||
250 | c.cm.findEntry(c.pid).deleteChild(c.id) | ||
251 | } | ||
252 | return true | ||
253 | } | ||
254 | |||
255 | // deleteSelfFromMap checks whether it is valid to delete the channel from the map, which means | ||
256 | // deleting the channel from channelz's tracking entirely. Users can no longer use id to query the | ||
257 | // channel, and its memory will be garbage collected. | ||
258 | // | ||
259 | // The trace reference count of the channel must be 0 in order to be deleted from the map. This is | ||
260 | // specified in the channel tracing gRFC that as long as some other trace has reference to an entity, | ||
261 | // the trace of the referenced entity must not be deleted. In order to release the resource allocated | ||
262 | // by grpc, the reference to the grpc object is reset to a dummy object. | ||
263 | // | ||
264 | // deleteSelfFromMap must be called after deleteSelfFromTree returns true. | ||
265 | // | ||
266 | // It returns a bool to indicate whether the channel can be safely deleted from map. | ||
267 | func (c *channel) deleteSelfFromMap() (delete bool) { | ||
268 | if c.getTraceRefCount() != 0 { | ||
269 | c.c = &dummyChannel{} | ||
270 | return false | ||
271 | } | ||
272 | return true | ||
273 | } | ||
274 | |||
275 | // deleteSelfIfReady tries to delete the channel itself from the channelz database. | ||
276 | // The delete process includes two steps: | ||
277 | // 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its | ||
278 | // parent's child list. | ||
279 | // 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id | ||
280 | // will return entry not found error. | ||
281 | func (c *channel) deleteSelfIfReady() { | ||
282 | if !c.deleteSelfFromTree() { | ||
283 | return | ||
284 | } | ||
285 | if !c.deleteSelfFromMap() { | ||
286 | return | ||
287 | } | ||
288 | c.cm.deleteEntry(c.id) | ||
289 | c.trace.clear() | ||
290 | } | ||
291 | |||
292 | func (c *channel) getChannelTrace() *channelTrace { | ||
293 | return c.trace | ||
294 | } | ||
295 | |||
296 | func (c *channel) incrTraceRefCount() { | ||
297 | atomic.AddInt32(&c.traceRefCount, 1) | ||
298 | } | ||
299 | |||
300 | func (c *channel) decrTraceRefCount() { | ||
301 | atomic.AddInt32(&c.traceRefCount, -1) | ||
302 | } | ||
303 | |||
304 | func (c *channel) getTraceRefCount() int { | ||
305 | i := atomic.LoadInt32(&c.traceRefCount) | ||
306 | return int(i) | ||
307 | } | ||
308 | |||
309 | func (c *channel) getRefName() string { | ||
310 | return c.refName | ||
311 | } | ||
312 | |||
313 | type subChannel struct { | ||
314 | refName string | ||
315 | c Channel | ||
316 | closeCalled bool | ||
317 | sockets map[int64]string | ||
318 | id int64 | ||
319 | pid int64 | ||
320 | cm *channelMap | ||
321 | trace *channelTrace | ||
322 | traceRefCount int32 | ||
323 | } | ||
324 | |||
325 | func (sc *subChannel) addChild(id int64, e entry) { | ||
326 | if v, ok := e.(*normalSocket); ok { | ||
327 | sc.sockets[id] = v.refName | ||
328 | } else { | ||
329 | grpclog.Errorf("cannot add a child (id = %d) of type %T to a subChannel", id, e) | ||
330 | } | ||
331 | } | ||
332 | |||
333 | func (sc *subChannel) deleteChild(id int64) { | ||
334 | delete(sc.sockets, id) | ||
335 | sc.deleteSelfIfReady() | ||
336 | } | ||
337 | |||
338 | func (sc *subChannel) triggerDelete() { | ||
339 | sc.closeCalled = true | ||
340 | sc.deleteSelfIfReady() | ||
341 | } | ||
342 | |||
343 | func (sc *subChannel) getParentID() int64 { | ||
344 | return sc.pid | ||
345 | } | ||
346 | |||
347 | // deleteSelfFromTree tries to delete the subchannel from the channelz entry relation tree, which | ||
348 | // means deleting the subchannel reference from its parent's child list. | ||
349 | // | ||
350 | // In order for a subchannel to be deleted from the tree, it must meet the criteria that, removal of | ||
351 | // the corresponding grpc object has been invoked, and the subchannel does not have any children left. | ||
352 | // | ||
353 | // The returned boolean value indicates whether the channel has been successfully deleted from tree. | ||
354 | func (sc *subChannel) deleteSelfFromTree() (deleted bool) { | ||
355 | if !sc.closeCalled || len(sc.sockets) != 0 { | ||
356 | return false | ||
357 | } | ||
358 | sc.cm.findEntry(sc.pid).deleteChild(sc.id) | ||
359 | return true | ||
360 | } | ||
361 | |||
362 | // deleteSelfFromMap checks whether it is valid to delete the subchannel from the map, which means | ||
363 | // deleting the subchannel from channelz's tracking entirely. Users can no longer use id to query | ||
364 | // the subchannel, and its memory will be garbage collected. | ||
365 | // | ||
366 | // The trace reference count of the subchannel must be 0 in order to be deleted from the map. This is | ||
367 | // specified in the channel tracing gRFC that as long as some other trace has reference to an entity, | ||
368 | // the trace of the referenced entity must not be deleted. In order to release the resource allocated | ||
369 | // by grpc, the reference to the grpc object is reset to a dummy object. | ||
370 | // | ||
371 | // deleteSelfFromMap must be called after deleteSelfFromTree returns true. | ||
372 | // | ||
373 | // It returns a bool to indicate whether the channel can be safely deleted from map. | ||
374 | func (sc *subChannel) deleteSelfFromMap() (delete bool) { | ||
375 | if sc.getTraceRefCount() != 0 { | ||
376 | // free the grpc struct (i.e. addrConn) | ||
377 | sc.c = &dummyChannel{} | ||
378 | return false | ||
379 | } | ||
380 | return true | ||
381 | } | ||
382 | |||
383 | // deleteSelfIfReady tries to delete the subchannel itself from the channelz database. | ||
384 | // The delete process includes two steps: | ||
385 | // 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from | ||
386 | // its parent's child list. | ||
387 | // 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup | ||
388 | // by id will return entry not found error. | ||
389 | func (sc *subChannel) deleteSelfIfReady() { | ||
390 | if !sc.deleteSelfFromTree() { | ||
391 | return | ||
392 | } | ||
393 | if !sc.deleteSelfFromMap() { | ||
394 | return | ||
395 | } | ||
396 | sc.cm.deleteEntry(sc.id) | ||
397 | sc.trace.clear() | ||
398 | } | ||
399 | |||
400 | func (sc *subChannel) getChannelTrace() *channelTrace { | ||
401 | return sc.trace | ||
402 | } | ||
403 | |||
404 | func (sc *subChannel) incrTraceRefCount() { | ||
405 | atomic.AddInt32(&sc.traceRefCount, 1) | ||
406 | } | ||
407 | |||
408 | func (sc *subChannel) decrTraceRefCount() { | ||
409 | atomic.AddInt32(&sc.traceRefCount, -1) | ||
410 | } | ||
411 | |||
412 | func (sc *subChannel) getTraceRefCount() int { | ||
413 | i := atomic.LoadInt32(&sc.traceRefCount) | ||
414 | return int(i) | ||
415 | } | ||
416 | |||
417 | func (sc *subChannel) getRefName() string { | ||
418 | return sc.refName | ||
419 | } | ||
420 | |||
421 | // SocketMetric defines the info channelz provides for a specific Socket, which | ||
422 | // includes SocketInternalMetric and channelz-specific data, such as channelz id, etc. | ||
423 | type SocketMetric struct { | ||
424 | // ID is the channelz id of this socket. | ||
425 | ID int64 | ||
426 | // RefName is the human readable reference string of this socket. | ||
427 | RefName string | ||
428 | // SocketData contains socket internal metric reported by the socket through | ||
429 | // ChannelzMetric(). | ||
430 | SocketData *SocketInternalMetric | ||
431 | } | ||
432 | |||
433 | // SocketInternalMetric defines the struct that the implementor of Socket interface | ||
434 | // should return from ChannelzMetric(). | ||
435 | type SocketInternalMetric struct { | ||
436 | // The number of streams that have been started. | ||
437 | StreamsStarted int64 | ||
438 | // The number of streams that have ended successfully: | ||
439 | // On client side, receiving frame with eos bit set. | ||
440 | // On server side, sending frame with eos bit set. | ||
441 | StreamsSucceeded int64 | ||
442 | // The number of streams that have ended unsuccessfully: | ||
443 | // On client side, termination without receiving frame with eos bit set. | ||
444 | // On server side, termination without sending frame with eos bit set. | ||
445 | StreamsFailed int64 | ||
446 | // The number of messages successfully sent on this socket. | ||
447 | MessagesSent int64 | ||
448 | MessagesReceived int64 | ||
449 | // The number of keep alives sent. This is typically implemented with HTTP/2 | ||
450 | // ping messages. | ||
451 | KeepAlivesSent int64 | ||
452 | // The last time a stream was created by this endpoint. Usually unset for | ||
453 | // servers. | ||
454 | LastLocalStreamCreatedTimestamp time.Time | ||
455 | // The last time a stream was created by the remote endpoint. Usually unset | ||
456 | // for clients. | ||
457 | LastRemoteStreamCreatedTimestamp time.Time | ||
458 | // The last time a message was sent by this endpoint. | ||
459 | LastMessageSentTimestamp time.Time | ||
460 | // The last time a message was received by this endpoint. | ||
461 | LastMessageReceivedTimestamp time.Time | ||
462 | // The amount of window, granted to the local endpoint by the remote endpoint. | ||
463 | // This may be slightly out of date due to network latency. This does NOT | ||
464 | // include stream level or TCP level flow control info. | ||
465 | LocalFlowControlWindow int64 | ||
466 | // The amount of window, granted to the remote endpoint by the local endpoint. | ||
467 | // This may be slightly out of date due to network latency. This does NOT | ||
468 | // include stream level or TCP level flow control info. | ||
469 | RemoteFlowControlWindow int64 | ||
470 | // The locally bound address. | ||
471 | LocalAddr net.Addr | ||
472 | // The remote bound address. May be absent. | ||
473 | RemoteAddr net.Addr | ||
474 | // Optional, represents the name of the remote endpoint, if different than | ||
475 | // the original target name. | ||
476 | RemoteName string | ||
477 | SocketOptions *SocketOptionData | ||
478 | Security credentials.ChannelzSecurityValue | ||
479 | } | ||
480 | |||
481 | // Socket is the interface that should be satisfied in order to be tracked by | ||
482 | // channelz as Socket. | ||
483 | type Socket interface { | ||
484 | ChannelzMetric() *SocketInternalMetric | ||
485 | } | ||
486 | |||
487 | type listenSocket struct { | ||
488 | refName string | ||
489 | s Socket | ||
490 | id int64 | ||
491 | pid int64 | ||
492 | cm *channelMap | ||
493 | } | ||
494 | |||
495 | func (ls *listenSocket) addChild(id int64, e entry) { | ||
496 | grpclog.Errorf("cannot add a child (id = %d) of type %T to a listen socket", id, e) | ||
497 | } | ||
498 | |||
499 | func (ls *listenSocket) deleteChild(id int64) { | ||
500 | grpclog.Errorf("cannot delete a child (id = %d) from a listen socket", id) | ||
501 | } | ||
502 | |||
503 | func (ls *listenSocket) triggerDelete() { | ||
504 | ls.cm.deleteEntry(ls.id) | ||
505 | ls.cm.findEntry(ls.pid).deleteChild(ls.id) | ||
506 | } | ||
507 | |||
508 | func (ls *listenSocket) deleteSelfIfReady() { | ||
509 | grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket") | ||
510 | } | ||
511 | |||
512 | func (ls *listenSocket) getParentID() int64 { | ||
513 | return ls.pid | ||
514 | } | ||
515 | |||
516 | type normalSocket struct { | ||
517 | refName string | ||
518 | s Socket | ||
519 | id int64 | ||
520 | pid int64 | ||
521 | cm *channelMap | ||
522 | } | ||
523 | |||
524 | func (ns *normalSocket) addChild(id int64, e entry) { | ||
525 | grpclog.Errorf("cannot add a child (id = %d) of type %T to a normal socket", id, e) | ||
526 | } | ||
527 | |||
528 | func (ns *normalSocket) deleteChild(id int64) { | ||
529 | grpclog.Errorf("cannot delete a child (id = %d) from a normal socket", id) | ||
530 | } | ||
531 | |||
532 | func (ns *normalSocket) triggerDelete() { | ||
533 | ns.cm.deleteEntry(ns.id) | ||
534 | ns.cm.findEntry(ns.pid).deleteChild(ns.id) | ||
535 | } | ||
536 | |||
537 | func (ns *normalSocket) deleteSelfIfReady() { | ||
538 | grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket") | ||
539 | } | ||
540 | |||
541 | func (ns *normalSocket) getParentID() int64 { | ||
542 | return ns.pid | ||
543 | } | ||
544 | |||
545 | // ServerMetric defines the info channelz provides for a specific Server, which | ||
546 | // includes ServerInternalMetric and channelz-specific data, such as channelz id, | ||
547 | // child list, etc. | ||
548 | type ServerMetric struct { | ||
549 | // ID is the channelz id of this server. | ||
550 | ID int64 | ||
551 | // RefName is the human readable reference string of this server. | ||
552 | RefName string | ||
553 | // ServerData contains server internal metric reported by the server through | ||
554 | // ChannelzMetric(). | ||
555 | ServerData *ServerInternalMetric | ||
556 | // ListenSockets tracks the listener socket type children of this server in the | ||
557 | // format of a map from socket channelz id to corresponding reference string. | ||
558 | ListenSockets map[int64]string | ||
559 | } | ||
560 | |||
561 | // ServerInternalMetric defines the struct that the implementor of Server interface | ||
562 | // should return from ChannelzMetric(). | ||
563 | type ServerInternalMetric struct { | ||
564 | // The number of incoming calls started on the server. | ||
565 | CallsStarted int64 | ||
566 | // The number of incoming calls that have completed with an OK status. | ||
567 | CallsSucceeded int64 | ||
568 | // The number of incoming calls that have a completed with a non-OK status. | ||
569 | CallsFailed int64 | ||
570 | // The last time a call was started on the server. | ||
571 | LastCallStartedTimestamp time.Time | ||
572 | } | ||
573 | |||
574 | // Server is the interface to be satisfied in order to be tracked by channelz as | ||
575 | // Server. | ||
576 | type Server interface { | ||
577 | ChannelzMetric() *ServerInternalMetric | ||
578 | } | ||
579 | |||
580 | type server struct { | ||
581 | refName string | ||
582 | s Server | ||
583 | closeCalled bool | ||
584 | sockets map[int64]string | ||
585 | listenSockets map[int64]string | ||
586 | id int64 | ||
587 | cm *channelMap | ||
588 | } | ||
589 | |||
590 | func (s *server) addChild(id int64, e entry) { | ||
591 | switch v := e.(type) { | ||
592 | case *normalSocket: | ||
593 | s.sockets[id] = v.refName | ||
594 | case *listenSocket: | ||
595 | s.listenSockets[id] = v.refName | ||
596 | default: | ||
597 | grpclog.Errorf("cannot add a child (id = %d) of type %T to a server", id, e) | ||
598 | } | ||
599 | } | ||
600 | |||
601 | func (s *server) deleteChild(id int64) { | ||
602 | delete(s.sockets, id) | ||
603 | delete(s.listenSockets, id) | ||
604 | s.deleteSelfIfReady() | ||
605 | } | ||
606 | |||
607 | func (s *server) triggerDelete() { | ||
608 | s.closeCalled = true | ||
609 | s.deleteSelfIfReady() | ||
610 | } | ||
611 | |||
612 | func (s *server) deleteSelfIfReady() { | ||
613 | if !s.closeCalled || len(s.sockets)+len(s.listenSockets) != 0 { | ||
614 | return | ||
615 | } | ||
616 | s.cm.deleteEntry(s.id) | ||
617 | } | ||
618 | |||
619 | func (s *server) getParentID() int64 { | ||
620 | return 0 | ||
621 | } | ||
622 | |||
623 | type tracedChannel interface { | ||
624 | getChannelTrace() *channelTrace | ||
625 | incrTraceRefCount() | ||
626 | decrTraceRefCount() | ||
627 | getRefName() string | ||
628 | } | ||
629 | |||
630 | type channelTrace struct { | ||
631 | cm *channelMap | ||
632 | createdTime time.Time | ||
633 | eventCount int64 | ||
634 | mu sync.Mutex | ||
635 | events []*TraceEvent | ||
636 | } | ||
637 | |||
638 | func (c *channelTrace) append(e *TraceEvent) { | ||
639 | c.mu.Lock() | ||
640 | if len(c.events) == getMaxTraceEntry() { | ||
641 | del := c.events[0] | ||
642 | c.events = c.events[1:] | ||
643 | if del.RefID != 0 { | ||
644 | // start recursive cleanup in a goroutine to not block the call originated from grpc. | ||
645 | go func() { | ||
646 | // need to acquire c.cm.mu lock to call the unlocked attemptCleanup func. | ||
647 | c.cm.mu.Lock() | ||
648 | c.cm.decrTraceRefCount(del.RefID) | ||
649 | c.cm.mu.Unlock() | ||
650 | }() | ||
651 | } | ||
652 | } | ||
653 | e.Timestamp = time.Now() | ||
654 | c.events = append(c.events, e) | ||
655 | c.eventCount++ | ||
656 | c.mu.Unlock() | ||
657 | } | ||
658 | |||
659 | func (c *channelTrace) clear() { | ||
660 | c.mu.Lock() | ||
661 | for _, e := range c.events { | ||
662 | if e.RefID != 0 { | ||
663 | // caller should have already held the c.cm.mu lock. | ||
664 | c.cm.decrTraceRefCount(e.RefID) | ||
665 | } | ||
666 | } | ||
667 | c.mu.Unlock() | ||
668 | } | ||
669 | |||
670 | // Severity is the severity level of a trace event. | ||
671 | // The canonical enumeration of all valid values is here: | ||
672 | // https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126. | ||
673 | type Severity int | ||
674 | |||
675 | const ( | ||
676 | // CtUNKNOWN indicates unknown severity of a trace event. | ||
677 | CtUNKNOWN Severity = iota | ||
678 | // CtINFO indicates info level severity of a trace event. | ||
679 | CtINFO | ||
680 | // CtWarning indicates warning level severity of a trace event. | ||
681 | CtWarning | ||
682 | // CtError indicates error level severity of a trace event. | ||
683 | CtError | ||
684 | ) | ||
685 | |||
686 | // RefChannelType is the type of the entity being referenced in a trace event. | ||
687 | type RefChannelType int | ||
688 | |||
689 | const ( | ||
690 | // RefChannel indicates the referenced entity is a Channel. | ||
691 | RefChannel RefChannelType = iota | ||
692 | // RefSubChannel indicates the referenced entity is a SubChannel. | ||
693 | RefSubChannel | ||
694 | ) | ||
695 | |||
696 | func (c *channelTrace) dumpData() *ChannelTrace { | ||
697 | c.mu.Lock() | ||
698 | ct := &ChannelTrace{EventNum: c.eventCount, CreationTime: c.createdTime} | ||
699 | ct.Events = c.events[:len(c.events)] | ||
700 | c.mu.Unlock() | ||
701 | return ct | ||
702 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go new file mode 100644 index 0000000..692dd61 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go | |||
@@ -0,0 +1,53 @@ | |||
1 | // +build !appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package channelz | ||
22 | |||
23 | import ( | ||
24 | "syscall" | ||
25 | |||
26 | "golang.org/x/sys/unix" | ||
27 | ) | ||
28 | |||
29 | // SocketOptionData defines the struct to hold socket option data, and related | ||
30 | // getter function to obtain info from fd. | ||
31 | type SocketOptionData struct { | ||
32 | Linger *unix.Linger | ||
33 | RecvTimeout *unix.Timeval | ||
34 | SendTimeout *unix.Timeval | ||
35 | TCPInfo *unix.TCPInfo | ||
36 | } | ||
37 | |||
38 | // Getsockopt defines the function to get socket options requested by channelz. | ||
39 | // It is to be passed to syscall.RawConn.Control(). | ||
40 | func (s *SocketOptionData) Getsockopt(fd uintptr) { | ||
41 | if v, err := unix.GetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER); err == nil { | ||
42 | s.Linger = v | ||
43 | } | ||
44 | if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO); err == nil { | ||
45 | s.RecvTimeout = v | ||
46 | } | ||
47 | if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO); err == nil { | ||
48 | s.SendTimeout = v | ||
49 | } | ||
50 | if v, err := unix.GetsockoptTCPInfo(int(fd), syscall.SOL_TCP, syscall.TCP_INFO); err == nil { | ||
51 | s.TCPInfo = v | ||
52 | } | ||
53 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go new file mode 100644 index 0000000..79edbef --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go | |||
@@ -0,0 +1,44 @@ | |||
1 | // +build !linux appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package channelz | ||
22 | |||
23 | import ( | ||
24 | "sync" | ||
25 | |||
26 | "google.golang.org/grpc/grpclog" | ||
27 | ) | ||
28 | |||
29 | var once sync.Once | ||
30 | |||
31 | // SocketOptionData defines the struct to hold socket option data, and related | ||
32 | // getter function to obtain info from fd. | ||
33 | // Windows OS doesn't support Socket Option | ||
34 | type SocketOptionData struct { | ||
35 | } | ||
36 | |||
37 | // Getsockopt defines the function to get socket options requested by channelz. | ||
38 | // It is to be passed to syscall.RawConn.Control(). | ||
39 | // Windows OS doesn't support Socket Option | ||
40 | func (s *SocketOptionData) Getsockopt(fd uintptr) { | ||
41 | once.Do(func() { | ||
42 | grpclog.Warningln("Channelz: socket options are not supported on non-linux os and appengine.") | ||
43 | }) | ||
44 | } | ||
diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_go18.go b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go index 93f0e1d..fdf409d 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_go18.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go | |||
@@ -1,8 +1,8 @@ | |||
1 | // +build go1.8 | 1 | // +build linux,!appengine |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * | 4 | * |
5 | * Copyright 2017 gRPC authors. | 5 | * Copyright 2018 gRPC authors. |
6 | * | 6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. | 8 | * you may not use this file except in compliance with the License. |
@@ -18,21 +18,22 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | package credentials | 21 | package channelz |
22 | 22 | ||
23 | import ( | 23 | import ( |
24 | "crypto/tls" | 24 | "syscall" |
25 | ) | 25 | ) |
26 | 26 | ||
27 | // cloneTLSConfig returns a shallow clone of the exported | 27 | // GetSocketOption gets the socket option info of the conn. |
28 | // fields of cfg, ignoring the unexported sync.Once, which | 28 | func GetSocketOption(socket interface{}) *SocketOptionData { |
29 | // contains a mutex and must not be copied. | 29 | c, ok := socket.(syscall.Conn) |
30 | // | 30 | if !ok { |
31 | // If cfg is nil, a new zero tls.Config is returned. | 31 | return nil |
32 | func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||
33 | if cfg == nil { | ||
34 | return &tls.Config{} | ||
35 | } | 32 | } |
36 | 33 | data := &SocketOptionData{} | |
37 | return cfg.Clone() | 34 | if rawConn, err := c.SyscallConn(); err == nil { |
35 | rawConn.Control(data.Getsockopt) | ||
36 | return data | ||
37 | } | ||
38 | return nil | ||
38 | } | 39 | } |
diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go new file mode 100644 index 0000000..8864a08 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go | |||
@@ -0,0 +1,26 @@ | |||
1 | // +build !linux appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package channelz | ||
22 | |||
23 | // GetSocketOption gets the socket option info of the conn. | ||
24 | func GetSocketOption(c interface{}) *SocketOptionData { | ||
25 | return nil | ||
26 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go new file mode 100644 index 0000000..d2193b3 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package envconfig contains grpc settings configured by environment variables. | ||
20 | package envconfig | ||
21 | |||
22 | import ( | ||
23 | "os" | ||
24 | "strings" | ||
25 | ) | ||
26 | |||
27 | const ( | ||
28 | prefix = "GRPC_GO_" | ||
29 | retryStr = prefix + "RETRY" | ||
30 | requireHandshakeStr = prefix + "REQUIRE_HANDSHAKE" | ||
31 | ) | ||
32 | |||
33 | // RequireHandshakeSetting describes the settings for handshaking. | ||
34 | type RequireHandshakeSetting int | ||
35 | |||
36 | const ( | ||
37 | // RequireHandshakeHybrid (default, deprecated) indicates to not wait for | ||
38 | // handshake before considering a connection ready, but wait before | ||
39 | // considering successful. | ||
40 | RequireHandshakeHybrid RequireHandshakeSetting = iota | ||
41 | // RequireHandshakeOn (default after the 1.17 release) indicates to wait | ||
42 | // for handshake before considering a connection ready/successful. | ||
43 | RequireHandshakeOn | ||
44 | // RequireHandshakeOff indicates to not wait for handshake before | ||
45 | // considering a connection ready/successful. | ||
46 | RequireHandshakeOff | ||
47 | ) | ||
48 | |||
49 | var ( | ||
50 | // Retry is set if retry is explicitly enabled via "GRPC_GO_RETRY=on". | ||
51 | Retry = strings.EqualFold(os.Getenv(retryStr), "on") | ||
52 | // RequireHandshake is set based upon the GRPC_GO_REQUIRE_HANDSHAKE | ||
53 | // environment variable. | ||
54 | // | ||
55 | // Will be removed after the 1.18 release. | ||
56 | RequireHandshake RequireHandshakeSetting | ||
57 | ) | ||
58 | |||
59 | func init() { | ||
60 | switch strings.ToLower(os.Getenv(requireHandshakeStr)) { | ||
61 | case "on": | ||
62 | default: | ||
63 | RequireHandshake = RequireHandshakeOn | ||
64 | case "off": | ||
65 | RequireHandshake = RequireHandshakeOff | ||
66 | case "hybrid": | ||
67 | // Will be removed after the 1.17 release. | ||
68 | RequireHandshake = RequireHandshakeHybrid | ||
69 | } | ||
70 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go new file mode 100644 index 0000000..200b115 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package grpcrand implements math/rand functions in a concurrent-safe way | ||
20 | // with a global random source, independent of math/rand's global source. | ||
21 | package grpcrand | ||
22 | |||
23 | import ( | ||
24 | "math/rand" | ||
25 | "sync" | ||
26 | "time" | ||
27 | ) | ||
28 | |||
29 | var ( | ||
30 | r = rand.New(rand.NewSource(time.Now().UnixNano())) | ||
31 | mu sync.Mutex | ||
32 | ) | ||
33 | |||
34 | // Int63n implements rand.Int63n on the grpcrand global source. | ||
35 | func Int63n(n int64) int64 { | ||
36 | mu.Lock() | ||
37 | res := r.Int63n(n) | ||
38 | mu.Unlock() | ||
39 | return res | ||
40 | } | ||
41 | |||
42 | // Intn implements rand.Intn on the grpcrand global source. | ||
43 | func Intn(n int) int { | ||
44 | mu.Lock() | ||
45 | res := r.Intn(n) | ||
46 | mu.Unlock() | ||
47 | return res | ||
48 | } | ||
49 | |||
50 | // Float64 implements rand.Float64 on the grpcrand global source. | ||
51 | func Float64() float64 { | ||
52 | mu.Lock() | ||
53 | res := r.Float64() | ||
54 | mu.Unlock() | ||
55 | return res | ||
56 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/event.go b/vendor/google.golang.org/grpc/internal/grpcsync/event.go new file mode 100644 index 0000000..fbe697c --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcsync/event.go | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package grpcsync implements additional synchronization primitives built upon | ||
20 | // the sync package. | ||
21 | package grpcsync | ||
22 | |||
23 | import ( | ||
24 | "sync" | ||
25 | "sync/atomic" | ||
26 | ) | ||
27 | |||
28 | // Event represents a one-time event that may occur in the future. | ||
29 | type Event struct { | ||
30 | fired int32 | ||
31 | c chan struct{} | ||
32 | o sync.Once | ||
33 | } | ||
34 | |||
35 | // Fire causes e to complete. It is safe to call multiple times, and | ||
36 | // concurrently. It returns true iff this call to Fire caused the signaling | ||
37 | // channel returned by Done to close. | ||
38 | func (e *Event) Fire() bool { | ||
39 | ret := false | ||
40 | e.o.Do(func() { | ||
41 | atomic.StoreInt32(&e.fired, 1) | ||
42 | close(e.c) | ||
43 | ret = true | ||
44 | }) | ||
45 | return ret | ||
46 | } | ||
47 | |||
48 | // Done returns a channel that will be closed when Fire is called. | ||
49 | func (e *Event) Done() <-chan struct{} { | ||
50 | return e.c | ||
51 | } | ||
52 | |||
53 | // HasFired returns true if Fire has been called. | ||
54 | func (e *Event) HasFired() bool { | ||
55 | return atomic.LoadInt32(&e.fired) == 1 | ||
56 | } | ||
57 | |||
58 | // NewEvent returns a new, ready-to-use Event. | ||
59 | func NewEvent() *Event { | ||
60 | return &Event{c: make(chan struct{})} | ||
61 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index 0708383..eaa54d4 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go | |||
@@ -15,20 +15,36 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | // Package internal contains gRPC-internal code for testing, to avoid polluting | 18 | // Package internal contains gRPC-internal code, to avoid polluting |
19 | // the godoc of the top-level grpc package. | 19 | // the godoc of the top-level grpc package. It must not import any grpc |
20 | // symbols to avoid circular dependencies. | ||
20 | package internal | 21 | package internal |
21 | 22 | ||
22 | // TestingCloseConns closes all existing transports but keeps | 23 | import "context" |
23 | // grpcServer.lis accepting new connections. | ||
24 | // | ||
25 | // The provided grpcServer must be of type *grpc.Server. It is untyped | ||
26 | // for circular dependency reasons. | ||
27 | var TestingCloseConns func(grpcServer interface{}) | ||
28 | 24 | ||
29 | // TestingUseHandlerImpl enables the http.Handler-based server implementation. | 25 | var ( |
30 | // It must be called before Serve and requires TLS credentials. | 26 | // WithContextDialer is exported by dialoptions.go |
31 | // | 27 | WithContextDialer interface{} // func(context.Context, string) (net.Conn, error) grpc.DialOption |
32 | // The provided grpcServer must be of type *grpc.Server. It is untyped | 28 | // WithResolverBuilder is exported by dialoptions.go |
33 | // for circular dependency reasons. | 29 | WithResolverBuilder interface{} // func (resolver.Builder) grpc.DialOption |
34 | var TestingUseHandlerImpl func(grpcServer interface{}) | 30 | // WithHealthCheckFunc is not exported by dialoptions.go |
31 | WithHealthCheckFunc interface{} // func (HealthChecker) DialOption | ||
32 | // HealthCheckFunc is used to provide client-side LB channel health checking | ||
33 | HealthCheckFunc HealthChecker | ||
34 | // BalancerUnregister is exported by package balancer to unregister a balancer. | ||
35 | BalancerUnregister func(name string) | ||
36 | ) | ||
37 | |||
38 | // HealthChecker defines the signature of the client-side LB channel health checking function. | ||
39 | type HealthChecker func(ctx context.Context, newStream func() (interface{}, error), reportHealth func(bool), serviceName string) error | ||
40 | |||
41 | const ( | ||
42 | // CredsBundleModeFallback switches GoogleDefaultCreds to fallback mode. | ||
43 | CredsBundleModeFallback = "fallback" | ||
44 | // CredsBundleModeBalancer switches GoogleDefaultCreds to grpclb balancer | ||
45 | // mode. | ||
46 | CredsBundleModeBalancer = "balancer" | ||
47 | // CredsBundleModeBackendFromBalancer switches GoogleDefaultCreds to mode | ||
48 | // that supports backend returned by grpclb balancer. | ||
49 | CredsBundleModeBackendFromBalancer = "backend-from-balancer" | ||
50 | ) | ||
diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go new file mode 100644 index 0000000..43281a3 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go | |||
@@ -0,0 +1,114 @@ | |||
1 | // +build !appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | // Package syscall provides functionalities that grpc uses to get low-level operating system | ||
22 | // stats/info. | ||
23 | package syscall | ||
24 | |||
25 | import ( | ||
26 | "fmt" | ||
27 | "net" | ||
28 | "syscall" | ||
29 | "time" | ||
30 | |||
31 | "golang.org/x/sys/unix" | ||
32 | "google.golang.org/grpc/grpclog" | ||
33 | ) | ||
34 | |||
35 | // GetCPUTime returns the how much CPU time has passed since the start of this process. | ||
36 | func GetCPUTime() int64 { | ||
37 | var ts unix.Timespec | ||
38 | if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { | ||
39 | grpclog.Fatal(err) | ||
40 | } | ||
41 | return ts.Nano() | ||
42 | } | ||
43 | |||
44 | // Rusage is an alias for syscall.Rusage under linux non-appengine environment. | ||
45 | type Rusage syscall.Rusage | ||
46 | |||
47 | // GetRusage returns the resource usage of current process. | ||
48 | func GetRusage() (rusage *Rusage) { | ||
49 | rusage = new(Rusage) | ||
50 | syscall.Getrusage(syscall.RUSAGE_SELF, (*syscall.Rusage)(rusage)) | ||
51 | return | ||
52 | } | ||
53 | |||
54 | // CPUTimeDiff returns the differences of user CPU time and system CPU time used | ||
55 | // between two Rusage structs. | ||
56 | func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { | ||
57 | f := (*syscall.Rusage)(first) | ||
58 | l := (*syscall.Rusage)(latest) | ||
59 | var ( | ||
60 | utimeDiffs = l.Utime.Sec - f.Utime.Sec | ||
61 | utimeDiffus = l.Utime.Usec - f.Utime.Usec | ||
62 | stimeDiffs = l.Stime.Sec - f.Stime.Sec | ||
63 | stimeDiffus = l.Stime.Usec - f.Stime.Usec | ||
64 | ) | ||
65 | |||
66 | uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6 | ||
67 | sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6 | ||
68 | |||
69 | return uTimeElapsed, sTimeElapsed | ||
70 | } | ||
71 | |||
72 | // SetTCPUserTimeout sets the TCP user timeout on a connection's socket | ||
73 | func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { | ||
74 | tcpconn, ok := conn.(*net.TCPConn) | ||
75 | if !ok { | ||
76 | // not a TCP connection. exit early | ||
77 | return nil | ||
78 | } | ||
79 | rawConn, err := tcpconn.SyscallConn() | ||
80 | if err != nil { | ||
81 | return fmt.Errorf("error getting raw connection: %v", err) | ||
82 | } | ||
83 | err = rawConn.Control(func(fd uintptr) { | ||
84 | err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond)) | ||
85 | }) | ||
86 | if err != nil { | ||
87 | return fmt.Errorf("error setting option on socket: %v", err) | ||
88 | } | ||
89 | |||
90 | return nil | ||
91 | } | ||
92 | |||
93 | // GetTCPUserTimeout gets the TCP user timeout on a connection's socket | ||
94 | func GetTCPUserTimeout(conn net.Conn) (opt int, err error) { | ||
95 | tcpconn, ok := conn.(*net.TCPConn) | ||
96 | if !ok { | ||
97 | err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn) | ||
98 | return | ||
99 | } | ||
100 | rawConn, err := tcpconn.SyscallConn() | ||
101 | if err != nil { | ||
102 | err = fmt.Errorf("error getting raw connection: %v", err) | ||
103 | return | ||
104 | } | ||
105 | err = rawConn.Control(func(fd uintptr) { | ||
106 | opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT) | ||
107 | }) | ||
108 | if err != nil { | ||
109 | err = fmt.Errorf("error getting option on socket: %v", err) | ||
110 | return | ||
111 | } | ||
112 | |||
113 | return | ||
114 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go new file mode 100644 index 0000000..61678fe --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go | |||
@@ -0,0 +1,63 @@ | |||
1 | // +build !linux appengine | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2018 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package syscall | ||
22 | |||
23 | import ( | ||
24 | "net" | ||
25 | "time" | ||
26 | |||
27 | "google.golang.org/grpc/grpclog" | ||
28 | ) | ||
29 | |||
30 | func init() { | ||
31 | grpclog.Info("CPU time info is unavailable on non-linux or appengine environment.") | ||
32 | } | ||
33 | |||
34 | // GetCPUTime returns the how much CPU time has passed since the start of this process. | ||
35 | // It always returns 0 under non-linux or appengine environment. | ||
36 | func GetCPUTime() int64 { | ||
37 | return 0 | ||
38 | } | ||
39 | |||
40 | // Rusage is an empty struct under non-linux or appengine environment. | ||
41 | type Rusage struct{} | ||
42 | |||
43 | // GetRusage is a no-op function under non-linux or appengine environment. | ||
44 | func GetRusage() (rusage *Rusage) { | ||
45 | return nil | ||
46 | } | ||
47 | |||
48 | // CPUTimeDiff returns the differences of user CPU time and system CPU time used | ||
49 | // between two Rusage structs. It a no-op function for non-linux or appengine environment. | ||
50 | func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { | ||
51 | return 0, 0 | ||
52 | } | ||
53 | |||
54 | // SetTCPUserTimeout is a no-op function under non-linux or appengine environments | ||
55 | func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { | ||
56 | return nil | ||
57 | } | ||
58 | |||
59 | // GetTCPUserTimeout is a no-op function under non-linux or appengine environments | ||
60 | // a negative return value indicates the operation is not supported | ||
61 | func GetTCPUserTimeout(conn net.Conn) (int, error) { | ||
62 | return -1, nil | ||
63 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/bdp_estimator.go b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go index 667edb8..070680e 100644 --- a/vendor/google.golang.org/grpc/transport/bdp_estimator.go +++ b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go | |||
@@ -24,9 +24,10 @@ import ( | |||
24 | ) | 24 | ) |
25 | 25 | ||
26 | const ( | 26 | const ( |
27 | // bdpLimit is the maximum value the flow control windows | 27 | // bdpLimit is the maximum value the flow control windows will be increased |
28 | // will be increased to. | 28 | // to. TCP typically limits this to 4MB, but some systems go up to 16MB. |
29 | bdpLimit = (1 << 20) * 4 | 29 | // Since this is only a limit, it is safe to make it optimistic. |
30 | bdpLimit = (1 << 20) * 16 | ||
30 | // alpha is a constant factor used to keep a moving average | 31 | // alpha is a constant factor used to keep a moving average |
31 | // of RTTs. | 32 | // of RTTs. |
32 | alpha = 0.9 | 33 | alpha = 0.9 |
@@ -41,12 +42,9 @@ const ( | |||
41 | gamma = 2 | 42 | gamma = 2 |
42 | ) | 43 | ) |
43 | 44 | ||
44 | var ( | 45 | // Adding arbitrary data to ping so that its ack can be identified. |
45 | // Adding arbitrary data to ping so that its ack can be | 46 | // Easter-egg: what does the ping message say? |
46 | // identified. | 47 | var bdpPing = &ping{data: [8]byte{2, 4, 16, 16, 9, 14, 7, 7}} |
47 | // Easter-egg: what does the ping message say? | ||
48 | bdpPing = &ping{data: [8]byte{2, 4, 16, 16, 9, 14, 7, 7}} | ||
49 | ) | ||
50 | 48 | ||
51 | type bdpEstimator struct { | 49 | type bdpEstimator struct { |
52 | // sentAt is the time when the ping was sent. | 50 | // sentAt is the time when the ping was sent. |
@@ -59,7 +57,7 @@ type bdpEstimator struct { | |||
59 | sample uint32 | 57 | sample uint32 |
60 | // bwMax is the maximum bandwidth noted so far (bytes/sec). | 58 | // bwMax is the maximum bandwidth noted so far (bytes/sec). |
61 | bwMax float64 | 59 | bwMax float64 |
62 | // bool to keep track of the begining of a new measurement cycle. | 60 | // bool to keep track of the beginning of a new measurement cycle. |
63 | isSent bool | 61 | isSent bool |
64 | // Callback to update the window sizes. | 62 | // Callback to update the window sizes. |
65 | updateFlowControl func(n uint32) | 63 | updateFlowControl func(n uint32) |
@@ -70,7 +68,7 @@ type bdpEstimator struct { | |||
70 | } | 68 | } |
71 | 69 | ||
72 | // timesnap registers the time bdp ping was sent out so that | 70 | // timesnap registers the time bdp ping was sent out so that |
73 | // network rtt can be calculated when its ack is recieved. | 71 | // network rtt can be calculated when its ack is received. |
74 | // It is called (by controller) when the bdpPing is | 72 | // It is called (by controller) when the bdpPing is |
75 | // being written on the wire. | 73 | // being written on the wire. |
76 | func (b *bdpEstimator) timesnap(d [8]byte) { | 74 | func (b *bdpEstimator) timesnap(d [8]byte) { |
@@ -119,7 +117,7 @@ func (b *bdpEstimator) calculate(d [8]byte) { | |||
119 | b.rtt += (rttSample - b.rtt) * float64(alpha) | 117 | b.rtt += (rttSample - b.rtt) * float64(alpha) |
120 | } | 118 | } |
121 | b.isSent = false | 119 | b.isSent = false |
122 | // The number of bytes accumalated so far in the sample is smaller | 120 | // The number of bytes accumulated so far in the sample is smaller |
123 | // than or equal to 1.5 times the real BDP on a saturated connection. | 121 | // than or equal to 1.5 times the real BDP on a saturated connection. |
124 | bwCurrent := float64(b.sample) / (b.rtt * float64(1.5)) | 122 | bwCurrent := float64(b.sample) / (b.rtt * float64(1.5)) |
125 | if bwCurrent > b.bwMax { | 123 | if bwCurrent > b.bwMax { |
diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go new file mode 100644 index 0000000..204ba15 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go | |||
@@ -0,0 +1,852 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2014 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package transport | ||
20 | |||
21 | import ( | ||
22 | "bytes" | ||
23 | "fmt" | ||
24 | "runtime" | ||
25 | "sync" | ||
26 | |||
27 | "golang.org/x/net/http2" | ||
28 | "golang.org/x/net/http2/hpack" | ||
29 | ) | ||
30 | |||
31 | var updateHeaderTblSize = func(e *hpack.Encoder, v uint32) { | ||
32 | e.SetMaxDynamicTableSizeLimit(v) | ||
33 | } | ||
34 | |||
35 | type itemNode struct { | ||
36 | it interface{} | ||
37 | next *itemNode | ||
38 | } | ||
39 | |||
40 | type itemList struct { | ||
41 | head *itemNode | ||
42 | tail *itemNode | ||
43 | } | ||
44 | |||
45 | func (il *itemList) enqueue(i interface{}) { | ||
46 | n := &itemNode{it: i} | ||
47 | if il.tail == nil { | ||
48 | il.head, il.tail = n, n | ||
49 | return | ||
50 | } | ||
51 | il.tail.next = n | ||
52 | il.tail = n | ||
53 | } | ||
54 | |||
55 | // peek returns the first item in the list without removing it from the | ||
56 | // list. | ||
57 | func (il *itemList) peek() interface{} { | ||
58 | return il.head.it | ||
59 | } | ||
60 | |||
61 | func (il *itemList) dequeue() interface{} { | ||
62 | if il.head == nil { | ||
63 | return nil | ||
64 | } | ||
65 | i := il.head.it | ||
66 | il.head = il.head.next | ||
67 | if il.head == nil { | ||
68 | il.tail = nil | ||
69 | } | ||
70 | return i | ||
71 | } | ||
72 | |||
73 | func (il *itemList) dequeueAll() *itemNode { | ||
74 | h := il.head | ||
75 | il.head, il.tail = nil, nil | ||
76 | return h | ||
77 | } | ||
78 | |||
79 | func (il *itemList) isEmpty() bool { | ||
80 | return il.head == nil | ||
81 | } | ||
82 | |||
83 | // The following defines various control items which could flow through | ||
84 | // the control buffer of transport. They represent different aspects of | ||
85 | // control tasks, e.g., flow control, settings, streaming resetting, etc. | ||
86 | |||
87 | // registerStream is used to register an incoming stream with loopy writer. | ||
88 | type registerStream struct { | ||
89 | streamID uint32 | ||
90 | wq *writeQuota | ||
91 | } | ||
92 | |||
93 | // headerFrame is also used to register stream on the client-side. | ||
94 | type headerFrame struct { | ||
95 | streamID uint32 | ||
96 | hf []hpack.HeaderField | ||
97 | endStream bool // Valid on server side. | ||
98 | initStream func(uint32) (bool, error) // Used only on the client side. | ||
99 | onWrite func() | ||
100 | wq *writeQuota // write quota for the stream created. | ||
101 | cleanup *cleanupStream // Valid on the server side. | ||
102 | onOrphaned func(error) // Valid on client-side | ||
103 | } | ||
104 | |||
105 | type cleanupStream struct { | ||
106 | streamID uint32 | ||
107 | rst bool | ||
108 | rstCode http2.ErrCode | ||
109 | onWrite func() | ||
110 | } | ||
111 | |||
112 | type dataFrame struct { | ||
113 | streamID uint32 | ||
114 | endStream bool | ||
115 | h []byte | ||
116 | d []byte | ||
117 | // onEachWrite is called every time | ||
118 | // a part of d is written out. | ||
119 | onEachWrite func() | ||
120 | } | ||
121 | |||
122 | type incomingWindowUpdate struct { | ||
123 | streamID uint32 | ||
124 | increment uint32 | ||
125 | } | ||
126 | |||
127 | type outgoingWindowUpdate struct { | ||
128 | streamID uint32 | ||
129 | increment uint32 | ||
130 | } | ||
131 | |||
132 | type incomingSettings struct { | ||
133 | ss []http2.Setting | ||
134 | } | ||
135 | |||
136 | type outgoingSettings struct { | ||
137 | ss []http2.Setting | ||
138 | } | ||
139 | |||
140 | type incomingGoAway struct { | ||
141 | } | ||
142 | |||
143 | type goAway struct { | ||
144 | code http2.ErrCode | ||
145 | debugData []byte | ||
146 | headsUp bool | ||
147 | closeConn bool | ||
148 | } | ||
149 | |||
150 | type ping struct { | ||
151 | ack bool | ||
152 | data [8]byte | ||
153 | } | ||
154 | |||
155 | type outFlowControlSizeRequest struct { | ||
156 | resp chan uint32 | ||
157 | } | ||
158 | |||
159 | type outStreamState int | ||
160 | |||
161 | const ( | ||
162 | active outStreamState = iota | ||
163 | empty | ||
164 | waitingOnStreamQuota | ||
165 | ) | ||
166 | |||
167 | type outStream struct { | ||
168 | id uint32 | ||
169 | state outStreamState | ||
170 | itl *itemList | ||
171 | bytesOutStanding int | ||
172 | wq *writeQuota | ||
173 | |||
174 | next *outStream | ||
175 | prev *outStream | ||
176 | } | ||
177 | |||
178 | func (s *outStream) deleteSelf() { | ||
179 | if s.prev != nil { | ||
180 | s.prev.next = s.next | ||
181 | } | ||
182 | if s.next != nil { | ||
183 | s.next.prev = s.prev | ||
184 | } | ||
185 | s.next, s.prev = nil, nil | ||
186 | } | ||
187 | |||
188 | type outStreamList struct { | ||
189 | // Following are sentinel objects that mark the | ||
190 | // beginning and end of the list. They do not | ||
191 | // contain any item lists. All valid objects are | ||
192 | // inserted in between them. | ||
193 | // This is needed so that an outStream object can | ||
194 | // deleteSelf() in O(1) time without knowing which | ||
195 | // list it belongs to. | ||
196 | head *outStream | ||
197 | tail *outStream | ||
198 | } | ||
199 | |||
200 | func newOutStreamList() *outStreamList { | ||
201 | head, tail := new(outStream), new(outStream) | ||
202 | head.next = tail | ||
203 | tail.prev = head | ||
204 | return &outStreamList{ | ||
205 | head: head, | ||
206 | tail: tail, | ||
207 | } | ||
208 | } | ||
209 | |||
210 | func (l *outStreamList) enqueue(s *outStream) { | ||
211 | e := l.tail.prev | ||
212 | e.next = s | ||
213 | s.prev = e | ||
214 | s.next = l.tail | ||
215 | l.tail.prev = s | ||
216 | } | ||
217 | |||
218 | // remove from the beginning of the list. | ||
219 | func (l *outStreamList) dequeue() *outStream { | ||
220 | b := l.head.next | ||
221 | if b == l.tail { | ||
222 | return nil | ||
223 | } | ||
224 | b.deleteSelf() | ||
225 | return b | ||
226 | } | ||
227 | |||
228 | // controlBuffer is a way to pass information to loopy. | ||
229 | // Information is passed as specific struct types called control frames. | ||
230 | // A control frame not only represents data, messages or headers to be sent out | ||
231 | // but can also be used to instruct loopy to update its internal state. | ||
232 | // It shouldn't be confused with an HTTP2 frame, although some of the control frames | ||
233 | // like dataFrame and headerFrame do go out on wire as HTTP2 frames. | ||
234 | type controlBuffer struct { | ||
235 | ch chan struct{} | ||
236 | done <-chan struct{} | ||
237 | mu sync.Mutex | ||
238 | consumerWaiting bool | ||
239 | list *itemList | ||
240 | err error | ||
241 | } | ||
242 | |||
243 | func newControlBuffer(done <-chan struct{}) *controlBuffer { | ||
244 | return &controlBuffer{ | ||
245 | ch: make(chan struct{}, 1), | ||
246 | list: &itemList{}, | ||
247 | done: done, | ||
248 | } | ||
249 | } | ||
250 | |||
251 | func (c *controlBuffer) put(it interface{}) error { | ||
252 | _, err := c.executeAndPut(nil, it) | ||
253 | return err | ||
254 | } | ||
255 | |||
256 | func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it interface{}) (bool, error) { | ||
257 | var wakeUp bool | ||
258 | c.mu.Lock() | ||
259 | if c.err != nil { | ||
260 | c.mu.Unlock() | ||
261 | return false, c.err | ||
262 | } | ||
263 | if f != nil { | ||
264 | if !f(it) { // f wasn't successful | ||
265 | c.mu.Unlock() | ||
266 | return false, nil | ||
267 | } | ||
268 | } | ||
269 | if c.consumerWaiting { | ||
270 | wakeUp = true | ||
271 | c.consumerWaiting = false | ||
272 | } | ||
273 | c.list.enqueue(it) | ||
274 | c.mu.Unlock() | ||
275 | if wakeUp { | ||
276 | select { | ||
277 | case c.ch <- struct{}{}: | ||
278 | default: | ||
279 | } | ||
280 | } | ||
281 | return true, nil | ||
282 | } | ||
283 | |||
284 | // Note argument f should never be nil. | ||
285 | func (c *controlBuffer) execute(f func(it interface{}) bool, it interface{}) (bool, error) { | ||
286 | c.mu.Lock() | ||
287 | if c.err != nil { | ||
288 | c.mu.Unlock() | ||
289 | return false, c.err | ||
290 | } | ||
291 | if !f(it) { // f wasn't successful | ||
292 | c.mu.Unlock() | ||
293 | return false, nil | ||
294 | } | ||
295 | c.mu.Unlock() | ||
296 | return true, nil | ||
297 | } | ||
298 | |||
299 | func (c *controlBuffer) get(block bool) (interface{}, error) { | ||
300 | for { | ||
301 | c.mu.Lock() | ||
302 | if c.err != nil { | ||
303 | c.mu.Unlock() | ||
304 | return nil, c.err | ||
305 | } | ||
306 | if !c.list.isEmpty() { | ||
307 | h := c.list.dequeue() | ||
308 | c.mu.Unlock() | ||
309 | return h, nil | ||
310 | } | ||
311 | if !block { | ||
312 | c.mu.Unlock() | ||
313 | return nil, nil | ||
314 | } | ||
315 | c.consumerWaiting = true | ||
316 | c.mu.Unlock() | ||
317 | select { | ||
318 | case <-c.ch: | ||
319 | case <-c.done: | ||
320 | c.finish() | ||
321 | return nil, ErrConnClosing | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | |||
326 | func (c *controlBuffer) finish() { | ||
327 | c.mu.Lock() | ||
328 | if c.err != nil { | ||
329 | c.mu.Unlock() | ||
330 | return | ||
331 | } | ||
332 | c.err = ErrConnClosing | ||
333 | // There may be headers for streams in the control buffer. | ||
334 | // These streams need to be cleaned out since the transport | ||
335 | // is still not aware of these yet. | ||
336 | for head := c.list.dequeueAll(); head != nil; head = head.next { | ||
337 | hdr, ok := head.it.(*headerFrame) | ||
338 | if !ok { | ||
339 | continue | ||
340 | } | ||
341 | if hdr.onOrphaned != nil { // It will be nil on the server-side. | ||
342 | hdr.onOrphaned(ErrConnClosing) | ||
343 | } | ||
344 | } | ||
345 | c.mu.Unlock() | ||
346 | } | ||
347 | |||
348 | type side int | ||
349 | |||
350 | const ( | ||
351 | clientSide side = iota | ||
352 | serverSide | ||
353 | ) | ||
354 | |||
355 | // Loopy receives frames from the control buffer. | ||
356 | // Each frame is handled individually; most of the work done by loopy goes | ||
357 | // into handling data frames. Loopy maintains a queue of active streams, and each | ||
358 | // stream maintains a queue of data frames; as loopy receives data frames | ||
359 | // it gets added to the queue of the relevant stream. | ||
360 | // Loopy goes over this list of active streams by processing one node every iteration, | ||
361 | // thereby closely resemebling to a round-robin scheduling over all streams. While | ||
362 | // processing a stream, loopy writes out data bytes from this stream capped by the min | ||
363 | // of http2MaxFrameLen, connection-level flow control and stream-level flow control. | ||
364 | type loopyWriter struct { | ||
365 | side side | ||
366 | cbuf *controlBuffer | ||
367 | sendQuota uint32 | ||
368 | oiws uint32 // outbound initial window size. | ||
369 | // estdStreams is map of all established streams that are not cleaned-up yet. | ||
370 | // On client-side, this is all streams whose headers were sent out. | ||
371 | // On server-side, this is all streams whose headers were received. | ||
372 | estdStreams map[uint32]*outStream // Established streams. | ||
373 | // activeStreams is a linked-list of all streams that have data to send and some | ||
374 | // stream-level flow control quota. | ||
375 | // Each of these streams internally have a list of data items(and perhaps trailers | ||
376 | // on the server-side) to be sent out. | ||
377 | activeStreams *outStreamList | ||
378 | framer *framer | ||
379 | hBuf *bytes.Buffer // The buffer for HPACK encoding. | ||
380 | hEnc *hpack.Encoder // HPACK encoder. | ||
381 | bdpEst *bdpEstimator | ||
382 | draining bool | ||
383 | |||
384 | // Side-specific handlers | ||
385 | ssGoAwayHandler func(*goAway) (bool, error) | ||
386 | } | ||
387 | |||
388 | func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimator) *loopyWriter { | ||
389 | var buf bytes.Buffer | ||
390 | l := &loopyWriter{ | ||
391 | side: s, | ||
392 | cbuf: cbuf, | ||
393 | sendQuota: defaultWindowSize, | ||
394 | oiws: defaultWindowSize, | ||
395 | estdStreams: make(map[uint32]*outStream), | ||
396 | activeStreams: newOutStreamList(), | ||
397 | framer: fr, | ||
398 | hBuf: &buf, | ||
399 | hEnc: hpack.NewEncoder(&buf), | ||
400 | bdpEst: bdpEst, | ||
401 | } | ||
402 | return l | ||
403 | } | ||
404 | |||
405 | const minBatchSize = 1000 | ||
406 | |||
407 | // run should be run in a separate goroutine. | ||
408 | // It reads control frames from controlBuf and processes them by: | ||
409 | // 1. Updating loopy's internal state, or/and | ||
410 | // 2. Writing out HTTP2 frames on the wire. | ||
411 | // | ||
412 | // Loopy keeps all active streams with data to send in a linked-list. | ||
413 | // All streams in the activeStreams linked-list must have both: | ||
414 | // 1. Data to send, and | ||
415 | // 2. Stream level flow control quota available. | ||
416 | // | ||
417 | // In each iteration of run loop, other than processing the incoming control | ||
418 | // frame, loopy calls processData, which processes one node from the activeStreams linked-list. | ||
419 | // This results in writing of HTTP2 frames into an underlying write buffer. | ||
420 | // When there's no more control frames to read from controlBuf, loopy flushes the write buffer. | ||
421 | // As an optimization, to increase the batch size for each flush, loopy yields the processor, once | ||
422 | // if the batch size is too low to give stream goroutines a chance to fill it up. | ||
423 | func (l *loopyWriter) run() (err error) { | ||
424 | defer func() { | ||
425 | if err == ErrConnClosing { | ||
426 | // Don't log ErrConnClosing as error since it happens | ||
427 | // 1. When the connection is closed by some other known issue. | ||
428 | // 2. User closed the connection. | ||
429 | // 3. A graceful close of connection. | ||
430 | infof("transport: loopyWriter.run returning. %v", err) | ||
431 | err = nil | ||
432 | } | ||
433 | }() | ||
434 | for { | ||
435 | it, err := l.cbuf.get(true) | ||
436 | if err != nil { | ||
437 | return err | ||
438 | } | ||
439 | if err = l.handle(it); err != nil { | ||
440 | return err | ||
441 | } | ||
442 | if _, err = l.processData(); err != nil { | ||
443 | return err | ||
444 | } | ||
445 | gosched := true | ||
446 | hasdata: | ||
447 | for { | ||
448 | it, err := l.cbuf.get(false) | ||
449 | if err != nil { | ||
450 | return err | ||
451 | } | ||
452 | if it != nil { | ||
453 | if err = l.handle(it); err != nil { | ||
454 | return err | ||
455 | } | ||
456 | if _, err = l.processData(); err != nil { | ||
457 | return err | ||
458 | } | ||
459 | continue hasdata | ||
460 | } | ||
461 | isEmpty, err := l.processData() | ||
462 | if err != nil { | ||
463 | return err | ||
464 | } | ||
465 | if !isEmpty { | ||
466 | continue hasdata | ||
467 | } | ||
468 | if gosched { | ||
469 | gosched = false | ||
470 | if l.framer.writer.offset < minBatchSize { | ||
471 | runtime.Gosched() | ||
472 | continue hasdata | ||
473 | } | ||
474 | } | ||
475 | l.framer.writer.Flush() | ||
476 | break hasdata | ||
477 | |||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | func (l *loopyWriter) outgoingWindowUpdateHandler(w *outgoingWindowUpdate) error { | ||
483 | return l.framer.fr.WriteWindowUpdate(w.streamID, w.increment) | ||
484 | } | ||
485 | |||
486 | func (l *loopyWriter) incomingWindowUpdateHandler(w *incomingWindowUpdate) error { | ||
487 | // Otherwise update the quota. | ||
488 | if w.streamID == 0 { | ||
489 | l.sendQuota += w.increment | ||
490 | return nil | ||
491 | } | ||
492 | // Find the stream and update it. | ||
493 | if str, ok := l.estdStreams[w.streamID]; ok { | ||
494 | str.bytesOutStanding -= int(w.increment) | ||
495 | if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota > 0 && str.state == waitingOnStreamQuota { | ||
496 | str.state = active | ||
497 | l.activeStreams.enqueue(str) | ||
498 | return nil | ||
499 | } | ||
500 | } | ||
501 | return nil | ||
502 | } | ||
503 | |||
504 | func (l *loopyWriter) outgoingSettingsHandler(s *outgoingSettings) error { | ||
505 | return l.framer.fr.WriteSettings(s.ss...) | ||
506 | } | ||
507 | |||
508 | func (l *loopyWriter) incomingSettingsHandler(s *incomingSettings) error { | ||
509 | if err := l.applySettings(s.ss); err != nil { | ||
510 | return err | ||
511 | } | ||
512 | return l.framer.fr.WriteSettingsAck() | ||
513 | } | ||
514 | |||
515 | func (l *loopyWriter) registerStreamHandler(h *registerStream) error { | ||
516 | str := &outStream{ | ||
517 | id: h.streamID, | ||
518 | state: empty, | ||
519 | itl: &itemList{}, | ||
520 | wq: h.wq, | ||
521 | } | ||
522 | l.estdStreams[h.streamID] = str | ||
523 | return nil | ||
524 | } | ||
525 | |||
526 | func (l *loopyWriter) headerHandler(h *headerFrame) error { | ||
527 | if l.side == serverSide { | ||
528 | str, ok := l.estdStreams[h.streamID] | ||
529 | if !ok { | ||
530 | warningf("transport: loopy doesn't recognize the stream: %d", h.streamID) | ||
531 | return nil | ||
532 | } | ||
533 | // Case 1.A: Server is responding back with headers. | ||
534 | if !h.endStream { | ||
535 | return l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite) | ||
536 | } | ||
537 | // else: Case 1.B: Server wants to close stream. | ||
538 | |||
539 | if str.state != empty { // either active or waiting on stream quota. | ||
540 | // add it str's list of items. | ||
541 | str.itl.enqueue(h) | ||
542 | return nil | ||
543 | } | ||
544 | if err := l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite); err != nil { | ||
545 | return err | ||
546 | } | ||
547 | return l.cleanupStreamHandler(h.cleanup) | ||
548 | } | ||
549 | // Case 2: Client wants to originate stream. | ||
550 | str := &outStream{ | ||
551 | id: h.streamID, | ||
552 | state: empty, | ||
553 | itl: &itemList{}, | ||
554 | wq: h.wq, | ||
555 | } | ||
556 | str.itl.enqueue(h) | ||
557 | return l.originateStream(str) | ||
558 | } | ||
559 | |||
560 | func (l *loopyWriter) originateStream(str *outStream) error { | ||
561 | hdr := str.itl.dequeue().(*headerFrame) | ||
562 | sendPing, err := hdr.initStream(str.id) | ||
563 | if err != nil { | ||
564 | if err == ErrConnClosing { | ||
565 | return err | ||
566 | } | ||
567 | // Other errors(errStreamDrain) need not close transport. | ||
568 | return nil | ||
569 | } | ||
570 | if err = l.writeHeader(str.id, hdr.endStream, hdr.hf, hdr.onWrite); err != nil { | ||
571 | return err | ||
572 | } | ||
573 | l.estdStreams[str.id] = str | ||
574 | if sendPing { | ||
575 | return l.pingHandler(&ping{data: [8]byte{}}) | ||
576 | } | ||
577 | return nil | ||
578 | } | ||
579 | |||
580 | func (l *loopyWriter) writeHeader(streamID uint32, endStream bool, hf []hpack.HeaderField, onWrite func()) error { | ||
581 | if onWrite != nil { | ||
582 | onWrite() | ||
583 | } | ||
584 | l.hBuf.Reset() | ||
585 | for _, f := range hf { | ||
586 | if err := l.hEnc.WriteField(f); err != nil { | ||
587 | warningf("transport: loopyWriter.writeHeader encountered error while encoding headers:", err) | ||
588 | } | ||
589 | } | ||
590 | var ( | ||
591 | err error | ||
592 | endHeaders, first bool | ||
593 | ) | ||
594 | first = true | ||
595 | for !endHeaders { | ||
596 | size := l.hBuf.Len() | ||
597 | if size > http2MaxFrameLen { | ||
598 | size = http2MaxFrameLen | ||
599 | } else { | ||
600 | endHeaders = true | ||
601 | } | ||
602 | if first { | ||
603 | first = false | ||
604 | err = l.framer.fr.WriteHeaders(http2.HeadersFrameParam{ | ||
605 | StreamID: streamID, | ||
606 | BlockFragment: l.hBuf.Next(size), | ||
607 | EndStream: endStream, | ||
608 | EndHeaders: endHeaders, | ||
609 | }) | ||
610 | } else { | ||
611 | err = l.framer.fr.WriteContinuation( | ||
612 | streamID, | ||
613 | endHeaders, | ||
614 | l.hBuf.Next(size), | ||
615 | ) | ||
616 | } | ||
617 | if err != nil { | ||
618 | return err | ||
619 | } | ||
620 | } | ||
621 | return nil | ||
622 | } | ||
623 | |||
624 | func (l *loopyWriter) preprocessData(df *dataFrame) error { | ||
625 | str, ok := l.estdStreams[df.streamID] | ||
626 | if !ok { | ||
627 | return nil | ||
628 | } | ||
629 | // If we got data for a stream it means that | ||
630 | // stream was originated and the headers were sent out. | ||
631 | str.itl.enqueue(df) | ||
632 | if str.state == empty { | ||
633 | str.state = active | ||
634 | l.activeStreams.enqueue(str) | ||
635 | } | ||
636 | return nil | ||
637 | } | ||
638 | |||
639 | func (l *loopyWriter) pingHandler(p *ping) error { | ||
640 | if !p.ack { | ||
641 | l.bdpEst.timesnap(p.data) | ||
642 | } | ||
643 | return l.framer.fr.WritePing(p.ack, p.data) | ||
644 | |||
645 | } | ||
646 | |||
647 | func (l *loopyWriter) outFlowControlSizeRequestHandler(o *outFlowControlSizeRequest) error { | ||
648 | o.resp <- l.sendQuota | ||
649 | return nil | ||
650 | } | ||
651 | |||
652 | func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error { | ||
653 | c.onWrite() | ||
654 | if str, ok := l.estdStreams[c.streamID]; ok { | ||
655 | // On the server side it could be a trailers-only response or | ||
656 | // a RST_STREAM before stream initialization thus the stream might | ||
657 | // not be established yet. | ||
658 | delete(l.estdStreams, c.streamID) | ||
659 | str.deleteSelf() | ||
660 | } | ||
661 | if c.rst { // If RST_STREAM needs to be sent. | ||
662 | if err := l.framer.fr.WriteRSTStream(c.streamID, c.rstCode); err != nil { | ||
663 | return err | ||
664 | } | ||
665 | } | ||
666 | if l.side == clientSide && l.draining && len(l.estdStreams) == 0 { | ||
667 | return ErrConnClosing | ||
668 | } | ||
669 | return nil | ||
670 | } | ||
671 | |||
672 | func (l *loopyWriter) incomingGoAwayHandler(*incomingGoAway) error { | ||
673 | if l.side == clientSide { | ||
674 | l.draining = true | ||
675 | if len(l.estdStreams) == 0 { | ||
676 | return ErrConnClosing | ||
677 | } | ||
678 | } | ||
679 | return nil | ||
680 | } | ||
681 | |||
682 | func (l *loopyWriter) goAwayHandler(g *goAway) error { | ||
683 | // Handling of outgoing GoAway is very specific to side. | ||
684 | if l.ssGoAwayHandler != nil { | ||
685 | draining, err := l.ssGoAwayHandler(g) | ||
686 | if err != nil { | ||
687 | return err | ||
688 | } | ||
689 | l.draining = draining | ||
690 | } | ||
691 | return nil | ||
692 | } | ||
693 | |||
694 | func (l *loopyWriter) handle(i interface{}) error { | ||
695 | switch i := i.(type) { | ||
696 | case *incomingWindowUpdate: | ||
697 | return l.incomingWindowUpdateHandler(i) | ||
698 | case *outgoingWindowUpdate: | ||
699 | return l.outgoingWindowUpdateHandler(i) | ||
700 | case *incomingSettings: | ||
701 | return l.incomingSettingsHandler(i) | ||
702 | case *outgoingSettings: | ||
703 | return l.outgoingSettingsHandler(i) | ||
704 | case *headerFrame: | ||
705 | return l.headerHandler(i) | ||
706 | case *registerStream: | ||
707 | return l.registerStreamHandler(i) | ||
708 | case *cleanupStream: | ||
709 | return l.cleanupStreamHandler(i) | ||
710 | case *incomingGoAway: | ||
711 | return l.incomingGoAwayHandler(i) | ||
712 | case *dataFrame: | ||
713 | return l.preprocessData(i) | ||
714 | case *ping: | ||
715 | return l.pingHandler(i) | ||
716 | case *goAway: | ||
717 | return l.goAwayHandler(i) | ||
718 | case *outFlowControlSizeRequest: | ||
719 | return l.outFlowControlSizeRequestHandler(i) | ||
720 | default: | ||
721 | return fmt.Errorf("transport: unknown control message type %T", i) | ||
722 | } | ||
723 | } | ||
724 | |||
725 | func (l *loopyWriter) applySettings(ss []http2.Setting) error { | ||
726 | for _, s := range ss { | ||
727 | switch s.ID { | ||
728 | case http2.SettingInitialWindowSize: | ||
729 | o := l.oiws | ||
730 | l.oiws = s.Val | ||
731 | if o < l.oiws { | ||
732 | // If the new limit is greater make all depleted streams active. | ||
733 | for _, stream := range l.estdStreams { | ||
734 | if stream.state == waitingOnStreamQuota { | ||
735 | stream.state = active | ||
736 | l.activeStreams.enqueue(stream) | ||
737 | } | ||
738 | } | ||
739 | } | ||
740 | case http2.SettingHeaderTableSize: | ||
741 | updateHeaderTblSize(l.hEnc, s.Val) | ||
742 | } | ||
743 | } | ||
744 | return nil | ||
745 | } | ||
746 | |||
747 | // processData removes the first stream from active streams, writes out at most 16KB | ||
748 | // of its data and then puts it at the end of activeStreams if there's still more data | ||
749 | // to be sent and stream has some stream-level flow control. | ||
750 | func (l *loopyWriter) processData() (bool, error) { | ||
751 | if l.sendQuota == 0 { | ||
752 | return true, nil | ||
753 | } | ||
754 | str := l.activeStreams.dequeue() // Remove the first stream. | ||
755 | if str == nil { | ||
756 | return true, nil | ||
757 | } | ||
758 | dataItem := str.itl.peek().(*dataFrame) // Peek at the first data item this stream. | ||
759 | // A data item is represented by a dataFrame, since it later translates into | ||
760 | // multiple HTTP2 data frames. | ||
761 | // Every dataFrame has two buffers; h that keeps grpc-message header and d that is acutal data. | ||
762 | // As an optimization to keep wire traffic low, data from d is copied to h to make as big as the | ||
763 | // maximum possilbe HTTP2 frame size. | ||
764 | |||
765 | if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // Empty data frame | ||
766 | // Client sends out empty data frame with endStream = true | ||
767 | if err := l.framer.fr.WriteData(dataItem.streamID, dataItem.endStream, nil); err != nil { | ||
768 | return false, err | ||
769 | } | ||
770 | str.itl.dequeue() // remove the empty data item from stream | ||
771 | if str.itl.isEmpty() { | ||
772 | str.state = empty | ||
773 | } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // the next item is trailers. | ||
774 | if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil { | ||
775 | return false, err | ||
776 | } | ||
777 | if err := l.cleanupStreamHandler(trailer.cleanup); err != nil { | ||
778 | return false, nil | ||
779 | } | ||
780 | } else { | ||
781 | l.activeStreams.enqueue(str) | ||
782 | } | ||
783 | return false, nil | ||
784 | } | ||
785 | var ( | ||
786 | idx int | ||
787 | buf []byte | ||
788 | ) | ||
789 | if len(dataItem.h) != 0 { // data header has not been written out yet. | ||
790 | buf = dataItem.h | ||
791 | } else { | ||
792 | idx = 1 | ||
793 | buf = dataItem.d | ||
794 | } | ||
795 | size := http2MaxFrameLen | ||
796 | if len(buf) < size { | ||
797 | size = len(buf) | ||
798 | } | ||
799 | if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { // stream-level flow control. | ||
800 | str.state = waitingOnStreamQuota | ||
801 | return false, nil | ||
802 | } else if strQuota < size { | ||
803 | size = strQuota | ||
804 | } | ||
805 | |||
806 | if l.sendQuota < uint32(size) { // connection-level flow control. | ||
807 | size = int(l.sendQuota) | ||
808 | } | ||
809 | // Now that outgoing flow controls are checked we can replenish str's write quota | ||
810 | str.wq.replenish(size) | ||
811 | var endStream bool | ||
812 | // If this is the last data message on this stream and all of it can be written in this iteration. | ||
813 | if dataItem.endStream && size == len(buf) { | ||
814 | // buf contains either data or it contains header but data is empty. | ||
815 | if idx == 1 || len(dataItem.d) == 0 { | ||
816 | endStream = true | ||
817 | } | ||
818 | } | ||
819 | if dataItem.onEachWrite != nil { | ||
820 | dataItem.onEachWrite() | ||
821 | } | ||
822 | if err := l.framer.fr.WriteData(dataItem.streamID, endStream, buf[:size]); err != nil { | ||
823 | return false, err | ||
824 | } | ||
825 | buf = buf[size:] | ||
826 | str.bytesOutStanding += size | ||
827 | l.sendQuota -= uint32(size) | ||
828 | if idx == 0 { | ||
829 | dataItem.h = buf | ||
830 | } else { | ||
831 | dataItem.d = buf | ||
832 | } | ||
833 | |||
834 | if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // All the data from that message was written out. | ||
835 | str.itl.dequeue() | ||
836 | } | ||
837 | if str.itl.isEmpty() { | ||
838 | str.state = empty | ||
839 | } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // The next item is trailers. | ||
840 | if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil { | ||
841 | return false, err | ||
842 | } | ||
843 | if err := l.cleanupStreamHandler(trailer.cleanup); err != nil { | ||
844 | return false, err | ||
845 | } | ||
846 | } else if int(l.oiws)-str.bytesOutStanding <= 0 { // Ran out of stream quota. | ||
847 | str.state = waitingOnStreamQuota | ||
848 | } else { // Otherwise add it back to the list of active streams. | ||
849 | l.activeStreams.enqueue(str) | ||
850 | } | ||
851 | return false, nil | ||
852 | } | ||
diff --git a/vendor/google.golang.org/grpc/internal/transport/defaults.go b/vendor/google.golang.org/grpc/internal/transport/defaults.go new file mode 100644 index 0000000..9fa306b --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/transport/defaults.go | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package transport | ||
20 | |||
21 | import ( | ||
22 | "math" | ||
23 | "time" | ||
24 | ) | ||
25 | |||
26 | const ( | ||
27 | // The default value of flow control window size in HTTP2 spec. | ||
28 | defaultWindowSize = 65535 | ||
29 | // The initial window size for flow control. | ||
30 | initialWindowSize = defaultWindowSize // for an RPC | ||
31 | infinity = time.Duration(math.MaxInt64) | ||
32 | defaultClientKeepaliveTime = infinity | ||
33 | defaultClientKeepaliveTimeout = 20 * time.Second | ||
34 | defaultMaxStreamsClient = 100 | ||
35 | defaultMaxConnectionIdle = infinity | ||
36 | defaultMaxConnectionAge = infinity | ||
37 | defaultMaxConnectionAgeGrace = infinity | ||
38 | defaultServerKeepaliveTime = 2 * time.Hour | ||
39 | defaultServerKeepaliveTimeout = 20 * time.Second | ||
40 | defaultKeepalivePolicyMinTime = 5 * time.Minute | ||
41 | // max window limit set by HTTP2 Specs. | ||
42 | maxWindowSize = math.MaxInt32 | ||
43 | // defaultWriteQuota is the default value for number of data | ||
44 | // bytes that each stream can schedule before some of it being | ||
45 | // flushed out. | ||
46 | defaultWriteQuota = 64 * 1024 | ||
47 | defaultClientMaxHeaderListSize = uint32(16 << 20) | ||
48 | defaultServerMaxHeaderListSize = uint32(16 << 20) | ||
49 | ) | ||
diff --git a/vendor/google.golang.org/grpc/transport/control.go b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go index 501eb03..5ea997a 100644 --- a/vendor/google.golang.org/grpc/transport/control.go +++ b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go | |||
@@ -22,128 +22,102 @@ import ( | |||
22 | "fmt" | 22 | "fmt" |
23 | "math" | 23 | "math" |
24 | "sync" | 24 | "sync" |
25 | "time" | 25 | "sync/atomic" |
26 | |||
27 | "golang.org/x/net/http2" | ||
28 | ) | ||
29 | |||
30 | const ( | ||
31 | // The default value of flow control window size in HTTP2 spec. | ||
32 | defaultWindowSize = 65535 | ||
33 | // The initial window size for flow control. | ||
34 | initialWindowSize = defaultWindowSize // for an RPC | ||
35 | infinity = time.Duration(math.MaxInt64) | ||
36 | defaultClientKeepaliveTime = infinity | ||
37 | defaultClientKeepaliveTimeout = time.Duration(20 * time.Second) | ||
38 | defaultMaxStreamsClient = 100 | ||
39 | defaultMaxConnectionIdle = infinity | ||
40 | defaultMaxConnectionAge = infinity | ||
41 | defaultMaxConnectionAgeGrace = infinity | ||
42 | defaultServerKeepaliveTime = time.Duration(2 * time.Hour) | ||
43 | defaultServerKeepaliveTimeout = time.Duration(20 * time.Second) | ||
44 | defaultKeepalivePolicyMinTime = time.Duration(5 * time.Minute) | ||
45 | // max window limit set by HTTP2 Specs. | ||
46 | maxWindowSize = math.MaxInt32 | ||
47 | ) | 26 | ) |
48 | 27 | ||
49 | // The following defines various control items which could flow through | 28 | // writeQuota is a soft limit on the amount of data a stream can |
50 | // the control buffer of transport. They represent different aspects of | 29 | // schedule before some of it is written out. |
51 | // control tasks, e.g., flow control, settings, streaming resetting, etc. | 30 | type writeQuota struct { |
52 | type windowUpdate struct { | 31 | quota int32 |
53 | streamID uint32 | 32 | // get waits on read from when quota goes less than or equal to zero. |
54 | increment uint32 | 33 | // replenish writes on it when quota goes positive again. |
55 | flush bool | 34 | ch chan struct{} |
56 | } | 35 | // done is triggered in error case. |
57 | 36 | done <-chan struct{} | |
58 | func (*windowUpdate) item() {} | 37 | // replenish is called by loopyWriter to give quota back to. |
59 | 38 | // It is implemented as a field so that it can be updated | |
60 | type settings struct { | 39 | // by tests. |
61 | ack bool | 40 | replenish func(n int) |
62 | ss []http2.Setting | 41 | } |
42 | |||
43 | func newWriteQuota(sz int32, done <-chan struct{}) *writeQuota { | ||
44 | w := &writeQuota{ | ||
45 | quota: sz, | ||
46 | ch: make(chan struct{}, 1), | ||
47 | done: done, | ||
48 | } | ||
49 | w.replenish = w.realReplenish | ||
50 | return w | ||
63 | } | 51 | } |
64 | 52 | ||
65 | func (*settings) item() {} | 53 | func (w *writeQuota) get(sz int32) error { |
66 | 54 | for { | |
67 | type resetStream struct { | 55 | if atomic.LoadInt32(&w.quota) > 0 { |
68 | streamID uint32 | 56 | atomic.AddInt32(&w.quota, -sz) |
69 | code http2.ErrCode | 57 | return nil |
58 | } | ||
59 | select { | ||
60 | case <-w.ch: | ||
61 | continue | ||
62 | case <-w.done: | ||
63 | return errStreamDone | ||
64 | } | ||
65 | } | ||
70 | } | 66 | } |
71 | 67 | ||
72 | func (*resetStream) item() {} | 68 | func (w *writeQuota) realReplenish(n int) { |
73 | 69 | sz := int32(n) | |
74 | type goAway struct { | 70 | a := atomic.AddInt32(&w.quota, sz) |
75 | code http2.ErrCode | 71 | b := a - sz |
76 | debugData []byte | 72 | if b <= 0 && a > 0 { |
77 | headsUp bool | 73 | select { |
78 | closeConn bool | 74 | case w.ch <- struct{}{}: |
75 | default: | ||
76 | } | ||
77 | } | ||
79 | } | 78 | } |
80 | 79 | ||
81 | func (*goAway) item() {} | 80 | type trInFlow struct { |
82 | 81 | limit uint32 | |
83 | type flushIO struct { | 82 | unacked uint32 |
83 | effectiveWindowSize uint32 | ||
84 | } | 84 | } |
85 | 85 | ||
86 | func (*flushIO) item() {} | 86 | func (f *trInFlow) newLimit(n uint32) uint32 { |
87 | 87 | d := n - f.limit | |
88 | type ping struct { | 88 | f.limit = n |
89 | ack bool | 89 | f.updateEffectiveWindowSize() |
90 | data [8]byte | 90 | return d |
91 | } | 91 | } |
92 | 92 | ||
93 | func (*ping) item() {} | 93 | func (f *trInFlow) onData(n uint32) uint32 { |
94 | 94 | f.unacked += n | |
95 | // quotaPool is a pool which accumulates the quota and sends it to acquire() | 95 | if f.unacked >= f.limit/4 { |
96 | // when it is available. | 96 | w := f.unacked |
97 | type quotaPool struct { | 97 | f.unacked = 0 |
98 | c chan int | 98 | f.updateEffectiveWindowSize() |
99 | 99 | return w | |
100 | mu sync.Mutex | 100 | } |
101 | quota int | 101 | f.updateEffectiveWindowSize() |
102 | return 0 | ||
102 | } | 103 | } |
103 | 104 | ||
104 | // newQuotaPool creates a quotaPool which has quota q available to consume. | 105 | func (f *trInFlow) reset() uint32 { |
105 | func newQuotaPool(q int) *quotaPool { | 106 | w := f.unacked |
106 | qb := "aPool{ | 107 | f.unacked = 0 |
107 | c: make(chan int, 1), | 108 | f.updateEffectiveWindowSize() |
108 | } | 109 | return w |
109 | if q > 0 { | ||
110 | qb.c <- q | ||
111 | } else { | ||
112 | qb.quota = q | ||
113 | } | ||
114 | return qb | ||
115 | } | 110 | } |
116 | 111 | ||
117 | // add cancels the pending quota sent on acquired, incremented by v and sends | 112 | func (f *trInFlow) updateEffectiveWindowSize() { |
118 | // it back on acquire. | 113 | atomic.StoreUint32(&f.effectiveWindowSize, f.limit-f.unacked) |
119 | func (qb *quotaPool) add(v int) { | ||
120 | qb.mu.Lock() | ||
121 | defer qb.mu.Unlock() | ||
122 | select { | ||
123 | case n := <-qb.c: | ||
124 | qb.quota += n | ||
125 | default: | ||
126 | } | ||
127 | qb.quota += v | ||
128 | if qb.quota <= 0 { | ||
129 | return | ||
130 | } | ||
131 | // After the pool has been created, this is the only place that sends on | ||
132 | // the channel. Since mu is held at this point and any quota that was sent | ||
133 | // on the channel has been retrieved, we know that this code will always | ||
134 | // place any positive quota value on the channel. | ||
135 | select { | ||
136 | case qb.c <- qb.quota: | ||
137 | qb.quota = 0 | ||
138 | default: | ||
139 | } | ||
140 | } | 114 | } |
141 | 115 | ||
142 | // acquire returns the channel on which available quota amounts are sent. | 116 | func (f *trInFlow) getSize() uint32 { |
143 | func (qb *quotaPool) acquire() <-chan int { | 117 | return atomic.LoadUint32(&f.effectiveWindowSize) |
144 | return qb.c | ||
145 | } | 118 | } |
146 | 119 | ||
120 | // TODO(mmukhi): Simplify this code. | ||
147 | // inFlow deals with inbound flow control | 121 | // inFlow deals with inbound flow control |
148 | type inFlow struct { | 122 | type inFlow struct { |
149 | mu sync.Mutex | 123 | mu sync.Mutex |
@@ -164,9 +138,9 @@ type inFlow struct { | |||
164 | // It assumes that n is always greater than the old limit. | 138 | // It assumes that n is always greater than the old limit. |
165 | func (f *inFlow) newLimit(n uint32) uint32 { | 139 | func (f *inFlow) newLimit(n uint32) uint32 { |
166 | f.mu.Lock() | 140 | f.mu.Lock() |
167 | defer f.mu.Unlock() | ||
168 | d := n - f.limit | 141 | d := n - f.limit |
169 | f.limit = n | 142 | f.limit = n |
143 | f.mu.Unlock() | ||
170 | return d | 144 | return d |
171 | } | 145 | } |
172 | 146 | ||
@@ -175,7 +149,6 @@ func (f *inFlow) maybeAdjust(n uint32) uint32 { | |||
175 | n = uint32(math.MaxInt32) | 149 | n = uint32(math.MaxInt32) |
176 | } | 150 | } |
177 | f.mu.Lock() | 151 | f.mu.Lock() |
178 | defer f.mu.Unlock() | ||
179 | // estSenderQuota is the receiver's view of the maximum number of bytes the sender | 152 | // estSenderQuota is the receiver's view of the maximum number of bytes the sender |
180 | // can send without a window update. | 153 | // can send without a window update. |
181 | estSenderQuota := int32(f.limit - (f.pendingData + f.pendingUpdate)) | 154 | estSenderQuota := int32(f.limit - (f.pendingData + f.pendingUpdate)) |
@@ -187,7 +160,7 @@ func (f *inFlow) maybeAdjust(n uint32) uint32 { | |||
187 | // for this message. Therefore we must send an update over the limit since there's an active read | 160 | // for this message. Therefore we must send an update over the limit since there's an active read |
188 | // request from the application. | 161 | // request from the application. |
189 | if estUntransmittedData > estSenderQuota { | 162 | if estUntransmittedData > estSenderQuota { |
190 | // Sender's window shouldn't go more than 2^31 - 1 as speecified in the HTTP spec. | 163 | // Sender's window shouldn't go more than 2^31 - 1 as specified in the HTTP spec. |
191 | if f.limit+n > maxWindowSize { | 164 | if f.limit+n > maxWindowSize { |
192 | f.delta = maxWindowSize - f.limit | 165 | f.delta = maxWindowSize - f.limit |
193 | } else { | 166 | } else { |
@@ -196,19 +169,24 @@ func (f *inFlow) maybeAdjust(n uint32) uint32 { | |||
196 | // is padded; We will fallback on the current available window(at least a 1/4th of the limit). | 169 | // is padded; We will fallback on the current available window(at least a 1/4th of the limit). |
197 | f.delta = n | 170 | f.delta = n |
198 | } | 171 | } |
172 | f.mu.Unlock() | ||
199 | return f.delta | 173 | return f.delta |
200 | } | 174 | } |
175 | f.mu.Unlock() | ||
201 | return 0 | 176 | return 0 |
202 | } | 177 | } |
203 | 178 | ||
204 | // onData is invoked when some data frame is received. It updates pendingData. | 179 | // onData is invoked when some data frame is received. It updates pendingData. |
205 | func (f *inFlow) onData(n uint32) error { | 180 | func (f *inFlow) onData(n uint32) error { |
206 | f.mu.Lock() | 181 | f.mu.Lock() |
207 | defer f.mu.Unlock() | ||
208 | f.pendingData += n | 182 | f.pendingData += n |
209 | if f.pendingData+f.pendingUpdate > f.limit+f.delta { | 183 | if f.pendingData+f.pendingUpdate > f.limit+f.delta { |
210 | return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", f.pendingData+f.pendingUpdate, f.limit) | 184 | limit := f.limit |
185 | rcvd := f.pendingData + f.pendingUpdate | ||
186 | f.mu.Unlock() | ||
187 | return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", rcvd, limit) | ||
211 | } | 188 | } |
189 | f.mu.Unlock() | ||
212 | return nil | 190 | return nil |
213 | } | 191 | } |
214 | 192 | ||
@@ -216,8 +194,8 @@ func (f *inFlow) onData(n uint32) error { | |||
216 | // to be sent to the peer. | 194 | // to be sent to the peer. |
217 | func (f *inFlow) onRead(n uint32) uint32 { | 195 | func (f *inFlow) onRead(n uint32) uint32 { |
218 | f.mu.Lock() | 196 | f.mu.Lock() |
219 | defer f.mu.Unlock() | ||
220 | if f.pendingData == 0 { | 197 | if f.pendingData == 0 { |
198 | f.mu.Unlock() | ||
221 | return 0 | 199 | return 0 |
222 | } | 200 | } |
223 | f.pendingData -= n | 201 | f.pendingData -= n |
@@ -232,15 +210,9 @@ func (f *inFlow) onRead(n uint32) uint32 { | |||
232 | if f.pendingUpdate >= f.limit/4 { | 210 | if f.pendingUpdate >= f.limit/4 { |
233 | wu := f.pendingUpdate | 211 | wu := f.pendingUpdate |
234 | f.pendingUpdate = 0 | 212 | f.pendingUpdate = 0 |
213 | f.mu.Unlock() | ||
235 | return wu | 214 | return wu |
236 | } | 215 | } |
216 | f.mu.Unlock() | ||
237 | return 0 | 217 | return 0 |
238 | } | 218 | } |
239 | |||
240 | func (f *inFlow) resetPendingUpdate() uint32 { | ||
241 | f.mu.Lock() | ||
242 | defer f.mu.Unlock() | ||
243 | n := f.pendingUpdate | ||
244 | f.pendingUpdate = 0 | ||
245 | return n | ||
246 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index 27372b5..73b41ea 100644 --- a/vendor/google.golang.org/grpc/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go | |||
@@ -24,6 +24,7 @@ | |||
24 | package transport | 24 | package transport |
25 | 25 | ||
26 | import ( | 26 | import ( |
27 | "context" | ||
27 | "errors" | 28 | "errors" |
28 | "fmt" | 29 | "fmt" |
29 | "io" | 30 | "io" |
@@ -33,26 +34,30 @@ import ( | |||
33 | "sync" | 34 | "sync" |
34 | "time" | 35 | "time" |
35 | 36 | ||
36 | "golang.org/x/net/context" | 37 | "github.com/golang/protobuf/proto" |
37 | "golang.org/x/net/http2" | 38 | "golang.org/x/net/http2" |
38 | "google.golang.org/grpc/codes" | 39 | "google.golang.org/grpc/codes" |
39 | "google.golang.org/grpc/credentials" | 40 | "google.golang.org/grpc/credentials" |
40 | "google.golang.org/grpc/metadata" | 41 | "google.golang.org/grpc/metadata" |
41 | "google.golang.org/grpc/peer" | 42 | "google.golang.org/grpc/peer" |
43 | "google.golang.org/grpc/stats" | ||
42 | "google.golang.org/grpc/status" | 44 | "google.golang.org/grpc/status" |
43 | ) | 45 | ) |
44 | 46 | ||
45 | // NewServerHandlerTransport returns a ServerTransport handling gRPC | 47 | // NewServerHandlerTransport returns a ServerTransport handling gRPC |
46 | // from inside an http.Handler. It requires that the http Server | 48 | // from inside an http.Handler. It requires that the http Server |
47 | // supports HTTP/2. | 49 | // supports HTTP/2. |
48 | func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request) (ServerTransport, error) { | 50 | func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler) (ServerTransport, error) { |
49 | if r.ProtoMajor != 2 { | 51 | if r.ProtoMajor != 2 { |
50 | return nil, errors.New("gRPC requires HTTP/2") | 52 | return nil, errors.New("gRPC requires HTTP/2") |
51 | } | 53 | } |
52 | if r.Method != "POST" { | 54 | if r.Method != "POST" { |
53 | return nil, errors.New("invalid gRPC request method") | 55 | return nil, errors.New("invalid gRPC request method") |
54 | } | 56 | } |
55 | if !validContentType(r.Header.Get("Content-Type")) { | 57 | contentType := r.Header.Get("Content-Type") |
58 | // TODO: do we assume contentType is lowercase? we did before | ||
59 | contentSubtype, validContentType := contentSubtype(contentType) | ||
60 | if !validContentType { | ||
56 | return nil, errors.New("invalid gRPC request content-type") | 61 | return nil, errors.New("invalid gRPC request content-type") |
57 | } | 62 | } |
58 | if _, ok := w.(http.Flusher); !ok { | 63 | if _, ok := w.(http.Flusher); !ok { |
@@ -63,34 +68,37 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request) (ServerTr | |||
63 | } | 68 | } |
64 | 69 | ||
65 | st := &serverHandlerTransport{ | 70 | st := &serverHandlerTransport{ |
66 | rw: w, | 71 | rw: w, |
67 | req: r, | 72 | req: r, |
68 | closedCh: make(chan struct{}), | 73 | closedCh: make(chan struct{}), |
69 | writes: make(chan func()), | 74 | writes: make(chan func()), |
75 | contentType: contentType, | ||
76 | contentSubtype: contentSubtype, | ||
77 | stats: stats, | ||
70 | } | 78 | } |
71 | 79 | ||
72 | if v := r.Header.Get("grpc-timeout"); v != "" { | 80 | if v := r.Header.Get("grpc-timeout"); v != "" { |
73 | to, err := decodeTimeout(v) | 81 | to, err := decodeTimeout(v) |
74 | if err != nil { | 82 | if err != nil { |
75 | return nil, streamErrorf(codes.Internal, "malformed time-out: %v", err) | 83 | return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err) |
76 | } | 84 | } |
77 | st.timeoutSet = true | 85 | st.timeoutSet = true |
78 | st.timeout = to | 86 | st.timeout = to |
79 | } | 87 | } |
80 | 88 | ||
81 | var metakv []string | 89 | metakv := []string{"content-type", contentType} |
82 | if r.Host != "" { | 90 | if r.Host != "" { |
83 | metakv = append(metakv, ":authority", r.Host) | 91 | metakv = append(metakv, ":authority", r.Host) |
84 | } | 92 | } |
85 | for k, vv := range r.Header { | 93 | for k, vv := range r.Header { |
86 | k = strings.ToLower(k) | 94 | k = strings.ToLower(k) |
87 | if isReservedHeader(k) && !isWhitelistedPseudoHeader(k) { | 95 | if isReservedHeader(k) && !isWhitelistedHeader(k) { |
88 | continue | 96 | continue |
89 | } | 97 | } |
90 | for _, v := range vv { | 98 | for _, v := range vv { |
91 | v, err := decodeMetadataHeader(k, v) | 99 | v, err := decodeMetadataHeader(k, v) |
92 | if err != nil { | 100 | if err != nil { |
93 | return nil, streamErrorf(codes.InvalidArgument, "malformed binary metadata: %v", err) | 101 | return nil, status.Errorf(codes.Internal, "malformed binary metadata: %v", err) |
94 | } | 102 | } |
95 | metakv = append(metakv, k, v) | 103 | metakv = append(metakv, k, v) |
96 | } | 104 | } |
@@ -121,6 +129,18 @@ type serverHandlerTransport struct { | |||
121 | // ServeHTTP (HandleStreams) goroutine. The channel is closed | 129 | // ServeHTTP (HandleStreams) goroutine. The channel is closed |
122 | // when WriteStatus is called. | 130 | // when WriteStatus is called. |
123 | writes chan func() | 131 | writes chan func() |
132 | |||
133 | // block concurrent WriteStatus calls | ||
134 | // e.g. grpc/(*serverStream).SendMsg/RecvMsg | ||
135 | writeStatusMu sync.Mutex | ||
136 | |||
137 | // we just mirror the request content-type | ||
138 | contentType string | ||
139 | // we store both contentType and contentSubtype so we don't keep recreating them | ||
140 | // TODO make sure this is consistent across handler_server and http2_server | ||
141 | contentSubtype string | ||
142 | |||
143 | stats stats.Handler | ||
124 | } | 144 | } |
125 | 145 | ||
126 | func (ht *serverHandlerTransport) Close() error { | 146 | func (ht *serverHandlerTransport) Close() error { |
@@ -167,11 +187,13 @@ func (ht *serverHandlerTransport) do(fn func()) error { | |||
167 | case <-ht.closedCh: | 187 | case <-ht.closedCh: |
168 | return ErrConnClosing | 188 | return ErrConnClosing |
169 | } | 189 | } |
170 | |||
171 | } | 190 | } |
172 | } | 191 | } |
173 | 192 | ||
174 | func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) error { | 193 | func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) error { |
194 | ht.writeStatusMu.Lock() | ||
195 | defer ht.writeStatusMu.Unlock() | ||
196 | |||
175 | err := ht.do(func() { | 197 | err := ht.do(func() { |
176 | ht.writeCommonHeaders(s) | 198 | ht.writeCommonHeaders(s) |
177 | 199 | ||
@@ -186,7 +208,15 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro | |||
186 | h.Set("Grpc-Message", encodeGrpcMessage(m)) | 208 | h.Set("Grpc-Message", encodeGrpcMessage(m)) |
187 | } | 209 | } |
188 | 210 | ||
189 | // TODO: Support Grpc-Status-Details-Bin | 211 | if p := st.Proto(); p != nil && len(p.Details) > 0 { |
212 | stBytes, err := proto.Marshal(p) | ||
213 | if err != nil { | ||
214 | // TODO: return error instead, when callers are able to handle it. | ||
215 | panic(err) | ||
216 | } | ||
217 | |||
218 | h.Set("Grpc-Status-Details-Bin", encodeBinHeader(stBytes)) | ||
219 | } | ||
190 | 220 | ||
191 | if md := s.Trailer(); len(md) > 0 { | 221 | if md := s.Trailer(); len(md) > 0 { |
192 | for k, vv := range md { | 222 | for k, vv := range md { |
@@ -202,7 +232,14 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro | |||
202 | } | 232 | } |
203 | } | 233 | } |
204 | }) | 234 | }) |
205 | close(ht.writes) | 235 | |
236 | if err == nil { // transport has not been closed | ||
237 | if ht.stats != nil { | ||
238 | ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{}) | ||
239 | } | ||
240 | close(ht.writes) | ||
241 | } | ||
242 | ht.Close() | ||
206 | return err | 243 | return err |
207 | } | 244 | } |
208 | 245 | ||
@@ -216,7 +253,7 @@ func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) { | |||
216 | 253 | ||
217 | h := ht.rw.Header() | 254 | h := ht.rw.Header() |
218 | h["Date"] = nil // suppress Date to make tests happy; TODO: restore | 255 | h["Date"] = nil // suppress Date to make tests happy; TODO: restore |
219 | h.Set("Content-Type", "application/grpc") | 256 | h.Set("Content-Type", ht.contentType) |
220 | 257 | ||
221 | // Predeclare trailers we'll set later in WriteStatus (after the body). | 258 | // Predeclare trailers we'll set later in WriteStatus (after the body). |
222 | // This is a SHOULD in the HTTP RFC, and the way you add (known) | 259 | // This is a SHOULD in the HTTP RFC, and the way you add (known) |
@@ -225,25 +262,24 @@ func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) { | |||
225 | // and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers | 262 | // and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers |
226 | h.Add("Trailer", "Grpc-Status") | 263 | h.Add("Trailer", "Grpc-Status") |
227 | h.Add("Trailer", "Grpc-Message") | 264 | h.Add("Trailer", "Grpc-Message") |
228 | // TODO: Support Grpc-Status-Details-Bin | 265 | h.Add("Trailer", "Grpc-Status-Details-Bin") |
229 | 266 | ||
230 | if s.sendCompress != "" { | 267 | if s.sendCompress != "" { |
231 | h.Set("Grpc-Encoding", s.sendCompress) | 268 | h.Set("Grpc-Encoding", s.sendCompress) |
232 | } | 269 | } |
233 | } | 270 | } |
234 | 271 | ||
235 | func (ht *serverHandlerTransport) Write(s *Stream, data []byte, opts *Options) error { | 272 | func (ht *serverHandlerTransport) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { |
236 | return ht.do(func() { | 273 | return ht.do(func() { |
237 | ht.writeCommonHeaders(s) | 274 | ht.writeCommonHeaders(s) |
275 | ht.rw.Write(hdr) | ||
238 | ht.rw.Write(data) | 276 | ht.rw.Write(data) |
239 | if !opts.Delay { | 277 | ht.rw.(http.Flusher).Flush() |
240 | ht.rw.(http.Flusher).Flush() | ||
241 | } | ||
242 | }) | 278 | }) |
243 | } | 279 | } |
244 | 280 | ||
245 | func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { | 281 | func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { |
246 | return ht.do(func() { | 282 | err := ht.do(func() { |
247 | ht.writeCommonHeaders(s) | 283 | ht.writeCommonHeaders(s) |
248 | h := ht.rw.Header() | 284 | h := ht.rw.Header() |
249 | for k, vv := range md { | 285 | for k, vv := range md { |
@@ -259,17 +295,24 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { | |||
259 | ht.rw.WriteHeader(200) | 295 | ht.rw.WriteHeader(200) |
260 | ht.rw.(http.Flusher).Flush() | 296 | ht.rw.(http.Flusher).Flush() |
261 | }) | 297 | }) |
298 | |||
299 | if err == nil { | ||
300 | if ht.stats != nil { | ||
301 | ht.stats.HandleRPC(s.Context(), &stats.OutHeader{}) | ||
302 | } | ||
303 | } | ||
304 | return err | ||
262 | } | 305 | } |
263 | 306 | ||
264 | func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) { | 307 | func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) { |
265 | // With this transport type there will be exactly 1 stream: this HTTP request. | 308 | // With this transport type there will be exactly 1 stream: this HTTP request. |
266 | 309 | ||
267 | var ctx context.Context | 310 | ctx := ht.req.Context() |
268 | var cancel context.CancelFunc | 311 | var cancel context.CancelFunc |
269 | if ht.timeoutSet { | 312 | if ht.timeoutSet { |
270 | ctx, cancel = context.WithTimeout(context.Background(), ht.timeout) | 313 | ctx, cancel = context.WithTimeout(ctx, ht.timeout) |
271 | } else { | 314 | } else { |
272 | ctx, cancel = context.WithCancel(context.Background()) | 315 | ctx, cancel = context.WithCancel(ctx) |
273 | } | 316 | } |
274 | 317 | ||
275 | // requestOver is closed when either the request's context is done | 318 | // requestOver is closed when either the request's context is done |
@@ -283,23 +326,24 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace | |||
283 | go func() { | 326 | go func() { |
284 | select { | 327 | select { |
285 | case <-requestOver: | 328 | case <-requestOver: |
286 | return | ||
287 | case <-ht.closedCh: | 329 | case <-ht.closedCh: |
288 | case <-clientGone: | 330 | case <-clientGone: |
289 | } | 331 | } |
290 | cancel() | 332 | cancel() |
333 | ht.Close() | ||
291 | }() | 334 | }() |
292 | 335 | ||
293 | req := ht.req | 336 | req := ht.req |
294 | 337 | ||
295 | s := &Stream{ | 338 | s := &Stream{ |
296 | id: 0, // irrelevant | 339 | id: 0, // irrelevant |
297 | requestRead: func(int) {}, | 340 | requestRead: func(int) {}, |
298 | cancel: cancel, | 341 | cancel: cancel, |
299 | buf: newRecvBuffer(), | 342 | buf: newRecvBuffer(), |
300 | st: ht, | 343 | st: ht, |
301 | method: req.URL.Path, | 344 | method: req.URL.Path, |
302 | recvCompress: req.Header.Get("grpc-encoding"), | 345 | recvCompress: req.Header.Get("grpc-encoding"), |
346 | contentSubtype: ht.contentSubtype, | ||
303 | } | 347 | } |
304 | pr := &peer.Peer{ | 348 | pr := &peer.Peer{ |
305 | Addr: ht.RemoteAddr(), | 349 | Addr: ht.RemoteAddr(), |
@@ -308,10 +352,18 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace | |||
308 | pr.AuthInfo = credentials.TLSInfo{State: *req.TLS} | 352 | pr.AuthInfo = credentials.TLSInfo{State: *req.TLS} |
309 | } | 353 | } |
310 | ctx = metadata.NewIncomingContext(ctx, ht.headerMD) | 354 | ctx = metadata.NewIncomingContext(ctx, ht.headerMD) |
311 | ctx = peer.NewContext(ctx, pr) | 355 | s.ctx = peer.NewContext(ctx, pr) |
312 | s.ctx = newContextWithStream(ctx, s) | 356 | if ht.stats != nil { |
357 | s.ctx = ht.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method}) | ||
358 | inHeader := &stats.InHeader{ | ||
359 | FullMethod: s.method, | ||
360 | RemoteAddr: ht.RemoteAddr(), | ||
361 | Compression: s.recvCompress, | ||
362 | } | ||
363 | ht.stats.HandleRPC(s.ctx, inHeader) | ||
364 | } | ||
313 | s.trReader = &transportReader{ | 365 | s.trReader = &transportReader{ |
314 | reader: &recvBufferReader{ctx: s.ctx, recv: s.buf}, | 366 | reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf}, |
315 | windowHandler: func(int) {}, | 367 | windowHandler: func(int) {}, |
316 | } | 368 | } |
317 | 369 | ||
@@ -366,6 +418,10 @@ func (ht *serverHandlerTransport) runStream() { | |||
366 | } | 418 | } |
367 | } | 419 | } |
368 | 420 | ||
421 | func (ht *serverHandlerTransport) IncrMsgSent() {} | ||
422 | |||
423 | func (ht *serverHandlerTransport) IncrMsgRecv() {} | ||
424 | |||
369 | func (ht *serverHandlerTransport) Drain() { | 425 | func (ht *serverHandlerTransport) Drain() { |
370 | panic("Drain() is not implemented") | 426 | panic("Drain() is not implemented") |
371 | } | 427 | } |
@@ -376,18 +432,18 @@ func (ht *serverHandlerTransport) Drain() { | |||
376 | // * io.EOF | 432 | // * io.EOF |
377 | // * io.ErrUnexpectedEOF | 433 | // * io.ErrUnexpectedEOF |
378 | // * of type transport.ConnectionError | 434 | // * of type transport.ConnectionError |
379 | // * of type transport.StreamError | 435 | // * an error from the status package |
380 | func mapRecvMsgError(err error) error { | 436 | func mapRecvMsgError(err error) error { |
381 | if err == io.EOF || err == io.ErrUnexpectedEOF { | 437 | if err == io.EOF || err == io.ErrUnexpectedEOF { |
382 | return err | 438 | return err |
383 | } | 439 | } |
384 | if se, ok := err.(http2.StreamError); ok { | 440 | if se, ok := err.(http2.StreamError); ok { |
385 | if code, ok := http2ErrConvTab[se.Code]; ok { | 441 | if code, ok := http2ErrConvTab[se.Code]; ok { |
386 | return StreamError{ | 442 | return status.Error(code, se.Error()) |
387 | Code: code, | ||
388 | Desc: se.Error(), | ||
389 | } | ||
390 | } | 443 | } |
391 | } | 444 | } |
445 | if strings.Contains(err.Error(), "body closed by handler") { | ||
446 | return status.Error(codes.Canceled, err.Error()) | ||
447 | } | ||
392 | return connectionErrorf(true, err, err.Error()) | 448 | return connectionErrorf(true, err, err.Error()) |
393 | } | 449 | } |
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go new file mode 100644 index 0000000..babcaee --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go | |||
@@ -0,0 +1,1380 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2014 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package transport | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | "fmt" | ||
24 | "io" | ||
25 | "math" | ||
26 | "net" | ||
27 | "strconv" | ||
28 | "strings" | ||
29 | "sync" | ||
30 | "sync/atomic" | ||
31 | "time" | ||
32 | |||
33 | "golang.org/x/net/http2" | ||
34 | "golang.org/x/net/http2/hpack" | ||
35 | |||
36 | "google.golang.org/grpc/codes" | ||
37 | "google.golang.org/grpc/credentials" | ||
38 | "google.golang.org/grpc/internal/channelz" | ||
39 | "google.golang.org/grpc/internal/syscall" | ||
40 | "google.golang.org/grpc/keepalive" | ||
41 | "google.golang.org/grpc/metadata" | ||
42 | "google.golang.org/grpc/peer" | ||
43 | "google.golang.org/grpc/stats" | ||
44 | "google.golang.org/grpc/status" | ||
45 | ) | ||
46 | |||
47 | // http2Client implements the ClientTransport interface with HTTP2. | ||
48 | type http2Client struct { | ||
49 | ctx context.Context | ||
50 | cancel context.CancelFunc | ||
51 | ctxDone <-chan struct{} // Cache the ctx.Done() chan. | ||
52 | userAgent string | ||
53 | md interface{} | ||
54 | conn net.Conn // underlying communication channel | ||
55 | loopy *loopyWriter | ||
56 | remoteAddr net.Addr | ||
57 | localAddr net.Addr | ||
58 | authInfo credentials.AuthInfo // auth info about the connection | ||
59 | |||
60 | readerDone chan struct{} // sync point to enable testing. | ||
61 | writerDone chan struct{} // sync point to enable testing. | ||
62 | // goAway is closed to notify the upper layer (i.e., addrConn.transportMonitor) | ||
63 | // that the server sent GoAway on this transport. | ||
64 | goAway chan struct{} | ||
65 | // awakenKeepalive is used to wake up keepalive when after it has gone dormant. | ||
66 | awakenKeepalive chan struct{} | ||
67 | |||
68 | framer *framer | ||
69 | // controlBuf delivers all the control related tasks (e.g., window | ||
70 | // updates, reset streams, and various settings) to the controller. | ||
71 | controlBuf *controlBuffer | ||
72 | fc *trInFlow | ||
73 | // The scheme used: https if TLS is on, http otherwise. | ||
74 | scheme string | ||
75 | |||
76 | isSecure bool | ||
77 | |||
78 | perRPCCreds []credentials.PerRPCCredentials | ||
79 | |||
80 | // Boolean to keep track of reading activity on transport. | ||
81 | // 1 is true and 0 is false. | ||
82 | activity uint32 // Accessed atomically. | ||
83 | kp keepalive.ClientParameters | ||
84 | keepaliveEnabled bool | ||
85 | |||
86 | statsHandler stats.Handler | ||
87 | |||
88 | initialWindowSize int32 | ||
89 | |||
90 | // configured by peer through SETTINGS_MAX_HEADER_LIST_SIZE | ||
91 | maxSendHeaderListSize *uint32 | ||
92 | |||
93 | bdpEst *bdpEstimator | ||
94 | // onPrefaceReceipt is a callback that client transport calls upon | ||
95 | // receiving server preface to signal that a succefull HTTP2 | ||
96 | // connection was established. | ||
97 | onPrefaceReceipt func() | ||
98 | |||
99 | maxConcurrentStreams uint32 | ||
100 | streamQuota int64 | ||
101 | streamsQuotaAvailable chan struct{} | ||
102 | waitingStreams uint32 | ||
103 | nextID uint32 | ||
104 | |||
105 | mu sync.Mutex // guard the following variables | ||
106 | state transportState | ||
107 | activeStreams map[uint32]*Stream | ||
108 | // prevGoAway ID records the Last-Stream-ID in the previous GOAway frame. | ||
109 | prevGoAwayID uint32 | ||
110 | // goAwayReason records the http2.ErrCode and debug data received with the | ||
111 | // GoAway frame. | ||
112 | goAwayReason GoAwayReason | ||
113 | |||
114 | // Fields below are for channelz metric collection. | ||
115 | channelzID int64 // channelz unique identification number | ||
116 | czData *channelzData | ||
117 | |||
118 | onGoAway func(GoAwayReason) | ||
119 | onClose func() | ||
120 | } | ||
121 | |||
122 | func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr string) (net.Conn, error) { | ||
123 | if fn != nil { | ||
124 | return fn(ctx, addr) | ||
125 | } | ||
126 | return (&net.Dialer{}).DialContext(ctx, "tcp", addr) | ||
127 | } | ||
128 | |||
129 | func isTemporary(err error) bool { | ||
130 | switch err := err.(type) { | ||
131 | case interface { | ||
132 | Temporary() bool | ||
133 | }: | ||
134 | return err.Temporary() | ||
135 | case interface { | ||
136 | Timeout() bool | ||
137 | }: | ||
138 | // Timeouts may be resolved upon retry, and are thus treated as | ||
139 | // temporary. | ||
140 | return err.Timeout() | ||
141 | } | ||
142 | return true | ||
143 | } | ||
144 | |||
145 | // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2 | ||
146 | // and starts to receive messages on it. Non-nil error returns if construction | ||
147 | // fails. | ||
148 | func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) { | ||
149 | scheme := "http" | ||
150 | ctx, cancel := context.WithCancel(ctx) | ||
151 | defer func() { | ||
152 | if err != nil { | ||
153 | cancel() | ||
154 | } | ||
155 | }() | ||
156 | |||
157 | conn, err := dial(connectCtx, opts.Dialer, addr.Addr) | ||
158 | if err != nil { | ||
159 | if opts.FailOnNonTempDialError { | ||
160 | return nil, connectionErrorf(isTemporary(err), err, "transport: error while dialing: %v", err) | ||
161 | } | ||
162 | return nil, connectionErrorf(true, err, "transport: Error while dialing %v", err) | ||
163 | } | ||
164 | // Any further errors will close the underlying connection | ||
165 | defer func(conn net.Conn) { | ||
166 | if err != nil { | ||
167 | conn.Close() | ||
168 | } | ||
169 | }(conn) | ||
170 | kp := opts.KeepaliveParams | ||
171 | // Validate keepalive parameters. | ||
172 | if kp.Time == 0 { | ||
173 | kp.Time = defaultClientKeepaliveTime | ||
174 | } | ||
175 | if kp.Timeout == 0 { | ||
176 | kp.Timeout = defaultClientKeepaliveTimeout | ||
177 | } | ||
178 | keepaliveEnabled := false | ||
179 | if kp.Time != infinity { | ||
180 | if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil { | ||
181 | return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err) | ||
182 | } | ||
183 | keepaliveEnabled = true | ||
184 | } | ||
185 | var ( | ||
186 | isSecure bool | ||
187 | authInfo credentials.AuthInfo | ||
188 | ) | ||
189 | transportCreds := opts.TransportCredentials | ||
190 | perRPCCreds := opts.PerRPCCredentials | ||
191 | |||
192 | if b := opts.CredsBundle; b != nil { | ||
193 | if t := b.TransportCredentials(); t != nil { | ||
194 | transportCreds = t | ||
195 | } | ||
196 | if t := b.PerRPCCredentials(); t != nil { | ||
197 | perRPCCreds = append(perRPCCreds, t) | ||
198 | } | ||
199 | } | ||
200 | if transportCreds != nil { | ||
201 | scheme = "https" | ||
202 | conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.Authority, conn) | ||
203 | if err != nil { | ||
204 | return nil, connectionErrorf(isTemporary(err), err, "transport: authentication handshake failed: %v", err) | ||
205 | } | ||
206 | isSecure = true | ||
207 | } | ||
208 | dynamicWindow := true | ||
209 | icwz := int32(initialWindowSize) | ||
210 | if opts.InitialConnWindowSize >= defaultWindowSize { | ||
211 | icwz = opts.InitialConnWindowSize | ||
212 | dynamicWindow = false | ||
213 | } | ||
214 | writeBufSize := opts.WriteBufferSize | ||
215 | readBufSize := opts.ReadBufferSize | ||
216 | maxHeaderListSize := defaultClientMaxHeaderListSize | ||
217 | if opts.MaxHeaderListSize != nil { | ||
218 | maxHeaderListSize = *opts.MaxHeaderListSize | ||
219 | } | ||
220 | t := &http2Client{ | ||
221 | ctx: ctx, | ||
222 | ctxDone: ctx.Done(), // Cache Done chan. | ||
223 | cancel: cancel, | ||
224 | userAgent: opts.UserAgent, | ||
225 | md: addr.Metadata, | ||
226 | conn: conn, | ||
227 | remoteAddr: conn.RemoteAddr(), | ||
228 | localAddr: conn.LocalAddr(), | ||
229 | authInfo: authInfo, | ||
230 | readerDone: make(chan struct{}), | ||
231 | writerDone: make(chan struct{}), | ||
232 | goAway: make(chan struct{}), | ||
233 | awakenKeepalive: make(chan struct{}, 1), | ||
234 | framer: newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize), | ||
235 | fc: &trInFlow{limit: uint32(icwz)}, | ||
236 | scheme: scheme, | ||
237 | activeStreams: make(map[uint32]*Stream), | ||
238 | isSecure: isSecure, | ||
239 | perRPCCreds: perRPCCreds, | ||
240 | kp: kp, | ||
241 | statsHandler: opts.StatsHandler, | ||
242 | initialWindowSize: initialWindowSize, | ||
243 | onPrefaceReceipt: onPrefaceReceipt, | ||
244 | nextID: 1, | ||
245 | maxConcurrentStreams: defaultMaxStreamsClient, | ||
246 | streamQuota: defaultMaxStreamsClient, | ||
247 | streamsQuotaAvailable: make(chan struct{}, 1), | ||
248 | czData: new(channelzData), | ||
249 | onGoAway: onGoAway, | ||
250 | onClose: onClose, | ||
251 | keepaliveEnabled: keepaliveEnabled, | ||
252 | } | ||
253 | t.controlBuf = newControlBuffer(t.ctxDone) | ||
254 | if opts.InitialWindowSize >= defaultWindowSize { | ||
255 | t.initialWindowSize = opts.InitialWindowSize | ||
256 | dynamicWindow = false | ||
257 | } | ||
258 | if dynamicWindow { | ||
259 | t.bdpEst = &bdpEstimator{ | ||
260 | bdp: initialWindowSize, | ||
261 | updateFlowControl: t.updateFlowControl, | ||
262 | } | ||
263 | } | ||
264 | // Make sure awakenKeepalive can't be written upon. | ||
265 | // keepalive routine will make it writable, if need be. | ||
266 | t.awakenKeepalive <- struct{}{} | ||
267 | if t.statsHandler != nil { | ||
268 | t.ctx = t.statsHandler.TagConn(t.ctx, &stats.ConnTagInfo{ | ||
269 | RemoteAddr: t.remoteAddr, | ||
270 | LocalAddr: t.localAddr, | ||
271 | }) | ||
272 | connBegin := &stats.ConnBegin{ | ||
273 | Client: true, | ||
274 | } | ||
275 | t.statsHandler.HandleConn(t.ctx, connBegin) | ||
276 | } | ||
277 | if channelz.IsOn() { | ||
278 | t.channelzID = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, fmt.Sprintf("%s -> %s", t.localAddr, t.remoteAddr)) | ||
279 | } | ||
280 | if t.keepaliveEnabled { | ||
281 | go t.keepalive() | ||
282 | } | ||
283 | // Start the reader goroutine for incoming message. Each transport has | ||
284 | // a dedicated goroutine which reads HTTP2 frame from network. Then it | ||
285 | // dispatches the frame to the corresponding stream entity. | ||
286 | go t.reader() | ||
287 | |||
288 | // Send connection preface to server. | ||
289 | n, err := t.conn.Write(clientPreface) | ||
290 | if err != nil { | ||
291 | t.Close() | ||
292 | return nil, connectionErrorf(true, err, "transport: failed to write client preface: %v", err) | ||
293 | } | ||
294 | if n != len(clientPreface) { | ||
295 | t.Close() | ||
296 | return nil, connectionErrorf(true, err, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) | ||
297 | } | ||
298 | var ss []http2.Setting | ||
299 | |||
300 | if t.initialWindowSize != defaultWindowSize { | ||
301 | ss = append(ss, http2.Setting{ | ||
302 | ID: http2.SettingInitialWindowSize, | ||
303 | Val: uint32(t.initialWindowSize), | ||
304 | }) | ||
305 | } | ||
306 | if opts.MaxHeaderListSize != nil { | ||
307 | ss = append(ss, http2.Setting{ | ||
308 | ID: http2.SettingMaxHeaderListSize, | ||
309 | Val: *opts.MaxHeaderListSize, | ||
310 | }) | ||
311 | } | ||
312 | err = t.framer.fr.WriteSettings(ss...) | ||
313 | if err != nil { | ||
314 | t.Close() | ||
315 | return nil, connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) | ||
316 | } | ||
317 | // Adjust the connection flow control window if needed. | ||
318 | if delta := uint32(icwz - defaultWindowSize); delta > 0 { | ||
319 | if err := t.framer.fr.WriteWindowUpdate(0, delta); err != nil { | ||
320 | t.Close() | ||
321 | return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err) | ||
322 | } | ||
323 | } | ||
324 | |||
325 | t.framer.writer.Flush() | ||
326 | go func() { | ||
327 | t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst) | ||
328 | err := t.loopy.run() | ||
329 | if err != nil { | ||
330 | errorf("transport: loopyWriter.run returning. Err: %v", err) | ||
331 | } | ||
332 | // If it's a connection error, let reader goroutine handle it | ||
333 | // since there might be data in the buffers. | ||
334 | if _, ok := err.(net.Error); !ok { | ||
335 | t.conn.Close() | ||
336 | } | ||
337 | close(t.writerDone) | ||
338 | }() | ||
339 | return t, nil | ||
340 | } | ||
341 | |||
342 | func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream { | ||
343 | // TODO(zhaoq): Handle uint32 overflow of Stream.id. | ||
344 | s := &Stream{ | ||
345 | done: make(chan struct{}), | ||
346 | method: callHdr.Method, | ||
347 | sendCompress: callHdr.SendCompress, | ||
348 | buf: newRecvBuffer(), | ||
349 | headerChan: make(chan struct{}), | ||
350 | contentSubtype: callHdr.ContentSubtype, | ||
351 | } | ||
352 | s.wq = newWriteQuota(defaultWriteQuota, s.done) | ||
353 | s.requestRead = func(n int) { | ||
354 | t.adjustWindow(s, uint32(n)) | ||
355 | } | ||
356 | // The client side stream context should have exactly the same life cycle with the user provided context. | ||
357 | // That means, s.ctx should be read-only. And s.ctx is done iff ctx is done. | ||
358 | // So we use the original context here instead of creating a copy. | ||
359 | s.ctx = ctx | ||
360 | s.trReader = &transportReader{ | ||
361 | reader: &recvBufferReader{ | ||
362 | ctx: s.ctx, | ||
363 | ctxDone: s.ctx.Done(), | ||
364 | recv: s.buf, | ||
365 | closeStream: func(err error) { | ||
366 | t.CloseStream(s, err) | ||
367 | }, | ||
368 | }, | ||
369 | windowHandler: func(n int) { | ||
370 | t.updateWindow(s, uint32(n)) | ||
371 | }, | ||
372 | } | ||
373 | return s | ||
374 | } | ||
375 | |||
376 | func (t *http2Client) getPeer() *peer.Peer { | ||
377 | pr := &peer.Peer{ | ||
378 | Addr: t.remoteAddr, | ||
379 | } | ||
380 | // Attach Auth info if there is any. | ||
381 | if t.authInfo != nil { | ||
382 | pr.AuthInfo = t.authInfo | ||
383 | } | ||
384 | return pr | ||
385 | } | ||
386 | |||
387 | func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) ([]hpack.HeaderField, error) { | ||
388 | aud := t.createAudience(callHdr) | ||
389 | authData, err := t.getTrAuthData(ctx, aud) | ||
390 | if err != nil { | ||
391 | return nil, err | ||
392 | } | ||
393 | callAuthData, err := t.getCallAuthData(ctx, aud, callHdr) | ||
394 | if err != nil { | ||
395 | return nil, err | ||
396 | } | ||
397 | // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields | ||
398 | // first and create a slice of that exact size. | ||
399 | // Make the slice of certain predictable size to reduce allocations made by append. | ||
400 | hfLen := 7 // :method, :scheme, :path, :authority, content-type, user-agent, te | ||
401 | hfLen += len(authData) + len(callAuthData) | ||
402 | headerFields := make([]hpack.HeaderField, 0, hfLen) | ||
403 | headerFields = append(headerFields, hpack.HeaderField{Name: ":method", Value: "POST"}) | ||
404 | headerFields = append(headerFields, hpack.HeaderField{Name: ":scheme", Value: t.scheme}) | ||
405 | headerFields = append(headerFields, hpack.HeaderField{Name: ":path", Value: callHdr.Method}) | ||
406 | headerFields = append(headerFields, hpack.HeaderField{Name: ":authority", Value: callHdr.Host}) | ||
407 | headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(callHdr.ContentSubtype)}) | ||
408 | headerFields = append(headerFields, hpack.HeaderField{Name: "user-agent", Value: t.userAgent}) | ||
409 | headerFields = append(headerFields, hpack.HeaderField{Name: "te", Value: "trailers"}) | ||
410 | if callHdr.PreviousAttempts > 0 { | ||
411 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)}) | ||
412 | } | ||
413 | |||
414 | if callHdr.SendCompress != "" { | ||
415 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) | ||
416 | } | ||
417 | if dl, ok := ctx.Deadline(); ok { | ||
418 | // Send out timeout regardless its value. The server can detect timeout context by itself. | ||
419 | // TODO(mmukhi): Perhaps this field should be updated when actually writing out to the wire. | ||
420 | timeout := dl.Sub(time.Now()) | ||
421 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-timeout", Value: encodeTimeout(timeout)}) | ||
422 | } | ||
423 | for k, v := range authData { | ||
424 | headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
425 | } | ||
426 | for k, v := range callAuthData { | ||
427 | headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
428 | } | ||
429 | if b := stats.OutgoingTags(ctx); b != nil { | ||
430 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-tags-bin", Value: encodeBinHeader(b)}) | ||
431 | } | ||
432 | if b := stats.OutgoingTrace(ctx); b != nil { | ||
433 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-trace-bin", Value: encodeBinHeader(b)}) | ||
434 | } | ||
435 | |||
436 | if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok { | ||
437 | var k string | ||
438 | for _, vv := range added { | ||
439 | for i, v := range vv { | ||
440 | if i%2 == 0 { | ||
441 | k = v | ||
442 | continue | ||
443 | } | ||
444 | // HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set. | ||
445 | if isReservedHeader(k) { | ||
446 | continue | ||
447 | } | ||
448 | headerFields = append(headerFields, hpack.HeaderField{Name: strings.ToLower(k), Value: encodeMetadataHeader(k, v)}) | ||
449 | } | ||
450 | } | ||
451 | for k, vv := range md { | ||
452 | // HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set. | ||
453 | if isReservedHeader(k) { | ||
454 | continue | ||
455 | } | ||
456 | for _, v := range vv { | ||
457 | headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | if md, ok := t.md.(*metadata.MD); ok { | ||
462 | for k, vv := range *md { | ||
463 | if isReservedHeader(k) { | ||
464 | continue | ||
465 | } | ||
466 | for _, v := range vv { | ||
467 | headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | return headerFields, nil | ||
472 | } | ||
473 | |||
474 | func (t *http2Client) createAudience(callHdr *CallHdr) string { | ||
475 | // Create an audience string only if needed. | ||
476 | if len(t.perRPCCreds) == 0 && callHdr.Creds == nil { | ||
477 | return "" | ||
478 | } | ||
479 | // Construct URI required to get auth request metadata. | ||
480 | // Omit port if it is the default one. | ||
481 | host := strings.TrimSuffix(callHdr.Host, ":443") | ||
482 | pos := strings.LastIndex(callHdr.Method, "/") | ||
483 | if pos == -1 { | ||
484 | pos = len(callHdr.Method) | ||
485 | } | ||
486 | return "https://" + host + callHdr.Method[:pos] | ||
487 | } | ||
488 | |||
489 | func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[string]string, error) { | ||
490 | authData := map[string]string{} | ||
491 | for _, c := range t.perRPCCreds { | ||
492 | data, err := c.GetRequestMetadata(ctx, audience) | ||
493 | if err != nil { | ||
494 | if _, ok := status.FromError(err); ok { | ||
495 | return nil, err | ||
496 | } | ||
497 | |||
498 | return nil, status.Errorf(codes.Unauthenticated, "transport: %v", err) | ||
499 | } | ||
500 | for k, v := range data { | ||
501 | // Capital header names are illegal in HTTP/2. | ||
502 | k = strings.ToLower(k) | ||
503 | authData[k] = v | ||
504 | } | ||
505 | } | ||
506 | return authData, nil | ||
507 | } | ||
508 | |||
509 | func (t *http2Client) getCallAuthData(ctx context.Context, audience string, callHdr *CallHdr) (map[string]string, error) { | ||
510 | callAuthData := map[string]string{} | ||
511 | // Check if credentials.PerRPCCredentials were provided via call options. | ||
512 | // Note: if these credentials are provided both via dial options and call | ||
513 | // options, then both sets of credentials will be applied. | ||
514 | if callCreds := callHdr.Creds; callCreds != nil { | ||
515 | if !t.isSecure && callCreds.RequireTransportSecurity() { | ||
516 | return nil, status.Error(codes.Unauthenticated, "transport: cannot send secure credentials on an insecure connection") | ||
517 | } | ||
518 | data, err := callCreds.GetRequestMetadata(ctx, audience) | ||
519 | if err != nil { | ||
520 | return nil, status.Errorf(codes.Internal, "transport: %v", err) | ||
521 | } | ||
522 | for k, v := range data { | ||
523 | // Capital header names are illegal in HTTP/2 | ||
524 | k = strings.ToLower(k) | ||
525 | callAuthData[k] = v | ||
526 | } | ||
527 | } | ||
528 | return callAuthData, nil | ||
529 | } | ||
530 | |||
531 | // NewStream creates a stream and registers it into the transport as "active" | ||
532 | // streams. | ||
533 | func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) { | ||
534 | ctx = peer.NewContext(ctx, t.getPeer()) | ||
535 | headerFields, err := t.createHeaderFields(ctx, callHdr) | ||
536 | if err != nil { | ||
537 | return nil, err | ||
538 | } | ||
539 | s := t.newStream(ctx, callHdr) | ||
540 | cleanup := func(err error) { | ||
541 | if s.swapState(streamDone) == streamDone { | ||
542 | // If it was already done, return. | ||
543 | return | ||
544 | } | ||
545 | // The stream was unprocessed by the server. | ||
546 | atomic.StoreUint32(&s.unprocessed, 1) | ||
547 | s.write(recvMsg{err: err}) | ||
548 | close(s.done) | ||
549 | // If headerChan isn't closed, then close it. | ||
550 | if atomic.SwapUint32(&s.headerDone, 1) == 0 { | ||
551 | close(s.headerChan) | ||
552 | } | ||
553 | |||
554 | } | ||
555 | hdr := &headerFrame{ | ||
556 | hf: headerFields, | ||
557 | endStream: false, | ||
558 | initStream: func(id uint32) (bool, error) { | ||
559 | t.mu.Lock() | ||
560 | if state := t.state; state != reachable { | ||
561 | t.mu.Unlock() | ||
562 | // Do a quick cleanup. | ||
563 | err := error(errStreamDrain) | ||
564 | if state == closing { | ||
565 | err = ErrConnClosing | ||
566 | } | ||
567 | cleanup(err) | ||
568 | return false, err | ||
569 | } | ||
570 | t.activeStreams[id] = s | ||
571 | if channelz.IsOn() { | ||
572 | atomic.AddInt64(&t.czData.streamsStarted, 1) | ||
573 | atomic.StoreInt64(&t.czData.lastStreamCreatedTime, time.Now().UnixNano()) | ||
574 | } | ||
575 | var sendPing bool | ||
576 | // If the number of active streams change from 0 to 1, then check if keepalive | ||
577 | // has gone dormant. If so, wake it up. | ||
578 | if len(t.activeStreams) == 1 && t.keepaliveEnabled { | ||
579 | select { | ||
580 | case t.awakenKeepalive <- struct{}{}: | ||
581 | sendPing = true | ||
582 | // Fill the awakenKeepalive channel again as this channel must be | ||
583 | // kept non-writable except at the point that the keepalive() | ||
584 | // goroutine is waiting either to be awaken or shutdown. | ||
585 | t.awakenKeepalive <- struct{}{} | ||
586 | default: | ||
587 | } | ||
588 | } | ||
589 | t.mu.Unlock() | ||
590 | return sendPing, nil | ||
591 | }, | ||
592 | onOrphaned: cleanup, | ||
593 | wq: s.wq, | ||
594 | } | ||
595 | firstTry := true | ||
596 | var ch chan struct{} | ||
597 | checkForStreamQuota := func(it interface{}) bool { | ||
598 | if t.streamQuota <= 0 { // Can go negative if server decreases it. | ||
599 | if firstTry { | ||
600 | t.waitingStreams++ | ||
601 | } | ||
602 | ch = t.streamsQuotaAvailable | ||
603 | return false | ||
604 | } | ||
605 | if !firstTry { | ||
606 | t.waitingStreams-- | ||
607 | } | ||
608 | t.streamQuota-- | ||
609 | h := it.(*headerFrame) | ||
610 | h.streamID = t.nextID | ||
611 | t.nextID += 2 | ||
612 | s.id = h.streamID | ||
613 | s.fc = &inFlow{limit: uint32(t.initialWindowSize)} | ||
614 | if t.streamQuota > 0 && t.waitingStreams > 0 { | ||
615 | select { | ||
616 | case t.streamsQuotaAvailable <- struct{}{}: | ||
617 | default: | ||
618 | } | ||
619 | } | ||
620 | return true | ||
621 | } | ||
622 | var hdrListSizeErr error | ||
623 | checkForHeaderListSize := func(it interface{}) bool { | ||
624 | if t.maxSendHeaderListSize == nil { | ||
625 | return true | ||
626 | } | ||
627 | hdrFrame := it.(*headerFrame) | ||
628 | var sz int64 | ||
629 | for _, f := range hdrFrame.hf { | ||
630 | if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { | ||
631 | hdrListSizeErr = status.Errorf(codes.Internal, "header list size to send violates the maximum size (%d bytes) set by server", *t.maxSendHeaderListSize) | ||
632 | return false | ||
633 | } | ||
634 | } | ||
635 | return true | ||
636 | } | ||
637 | for { | ||
638 | success, err := t.controlBuf.executeAndPut(func(it interface{}) bool { | ||
639 | if !checkForStreamQuota(it) { | ||
640 | return false | ||
641 | } | ||
642 | if !checkForHeaderListSize(it) { | ||
643 | return false | ||
644 | } | ||
645 | return true | ||
646 | }, hdr) | ||
647 | if err != nil { | ||
648 | return nil, err | ||
649 | } | ||
650 | if success { | ||
651 | break | ||
652 | } | ||
653 | if hdrListSizeErr != nil { | ||
654 | return nil, hdrListSizeErr | ||
655 | } | ||
656 | firstTry = false | ||
657 | select { | ||
658 | case <-ch: | ||
659 | case <-s.ctx.Done(): | ||
660 | return nil, ContextErr(s.ctx.Err()) | ||
661 | case <-t.goAway: | ||
662 | return nil, errStreamDrain | ||
663 | case <-t.ctx.Done(): | ||
664 | return nil, ErrConnClosing | ||
665 | } | ||
666 | } | ||
667 | if t.statsHandler != nil { | ||
668 | outHeader := &stats.OutHeader{ | ||
669 | Client: true, | ||
670 | FullMethod: callHdr.Method, | ||
671 | RemoteAddr: t.remoteAddr, | ||
672 | LocalAddr: t.localAddr, | ||
673 | Compression: callHdr.SendCompress, | ||
674 | } | ||
675 | t.statsHandler.HandleRPC(s.ctx, outHeader) | ||
676 | } | ||
677 | return s, nil | ||
678 | } | ||
679 | |||
680 | // CloseStream clears the footprint of a stream when the stream is not needed any more. | ||
681 | // This must not be executed in reader's goroutine. | ||
682 | func (t *http2Client) CloseStream(s *Stream, err error) { | ||
683 | var ( | ||
684 | rst bool | ||
685 | rstCode http2.ErrCode | ||
686 | ) | ||
687 | if err != nil { | ||
688 | rst = true | ||
689 | rstCode = http2.ErrCodeCancel | ||
690 | } | ||
691 | t.closeStream(s, err, rst, rstCode, status.Convert(err), nil, false) | ||
692 | } | ||
693 | |||
694 | func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.ErrCode, st *status.Status, mdata map[string][]string, eosReceived bool) { | ||
695 | // Set stream status to done. | ||
696 | if s.swapState(streamDone) == streamDone { | ||
697 | // If it was already done, return. If multiple closeStream calls | ||
698 | // happen simultaneously, wait for the first to finish. | ||
699 | <-s.done | ||
700 | return | ||
701 | } | ||
702 | // status and trailers can be updated here without any synchronization because the stream goroutine will | ||
703 | // only read it after it sees an io.EOF error from read or write and we'll write those errors | ||
704 | // only after updating this. | ||
705 | s.status = st | ||
706 | if len(mdata) > 0 { | ||
707 | s.trailer = mdata | ||
708 | } | ||
709 | if err != nil { | ||
710 | // This will unblock reads eventually. | ||
711 | s.write(recvMsg{err: err}) | ||
712 | } | ||
713 | // If headerChan isn't closed, then close it. | ||
714 | if atomic.SwapUint32(&s.headerDone, 1) == 0 { | ||
715 | s.noHeaders = true | ||
716 | close(s.headerChan) | ||
717 | } | ||
718 | cleanup := &cleanupStream{ | ||
719 | streamID: s.id, | ||
720 | onWrite: func() { | ||
721 | t.mu.Lock() | ||
722 | if t.activeStreams != nil { | ||
723 | delete(t.activeStreams, s.id) | ||
724 | } | ||
725 | t.mu.Unlock() | ||
726 | if channelz.IsOn() { | ||
727 | if eosReceived { | ||
728 | atomic.AddInt64(&t.czData.streamsSucceeded, 1) | ||
729 | } else { | ||
730 | atomic.AddInt64(&t.czData.streamsFailed, 1) | ||
731 | } | ||
732 | } | ||
733 | }, | ||
734 | rst: rst, | ||
735 | rstCode: rstCode, | ||
736 | } | ||
737 | addBackStreamQuota := func(interface{}) bool { | ||
738 | t.streamQuota++ | ||
739 | if t.streamQuota > 0 && t.waitingStreams > 0 { | ||
740 | select { | ||
741 | case t.streamsQuotaAvailable <- struct{}{}: | ||
742 | default: | ||
743 | } | ||
744 | } | ||
745 | return true | ||
746 | } | ||
747 | t.controlBuf.executeAndPut(addBackStreamQuota, cleanup) | ||
748 | // This will unblock write. | ||
749 | close(s.done) | ||
750 | } | ||
751 | |||
752 | // Close kicks off the shutdown process of the transport. This should be called | ||
753 | // only once on a transport. Once it is called, the transport should not be | ||
754 | // accessed any more. | ||
755 | // | ||
756 | // This method blocks until the addrConn that initiated this transport is | ||
757 | // re-connected. This happens because t.onClose() begins reconnect logic at the | ||
758 | // addrConn level and blocks until the addrConn is successfully connected. | ||
759 | func (t *http2Client) Close() error { | ||
760 | t.mu.Lock() | ||
761 | // Make sure we only Close once. | ||
762 | if t.state == closing { | ||
763 | t.mu.Unlock() | ||
764 | return nil | ||
765 | } | ||
766 | t.state = closing | ||
767 | streams := t.activeStreams | ||
768 | t.activeStreams = nil | ||
769 | t.mu.Unlock() | ||
770 | t.controlBuf.finish() | ||
771 | t.cancel() | ||
772 | err := t.conn.Close() | ||
773 | if channelz.IsOn() { | ||
774 | channelz.RemoveEntry(t.channelzID) | ||
775 | } | ||
776 | // Notify all active streams. | ||
777 | for _, s := range streams { | ||
778 | t.closeStream(s, ErrConnClosing, false, http2.ErrCodeNo, status.New(codes.Unavailable, ErrConnClosing.Desc), nil, false) | ||
779 | } | ||
780 | if t.statsHandler != nil { | ||
781 | connEnd := &stats.ConnEnd{ | ||
782 | Client: true, | ||
783 | } | ||
784 | t.statsHandler.HandleConn(t.ctx, connEnd) | ||
785 | } | ||
786 | t.onClose() | ||
787 | return err | ||
788 | } | ||
789 | |||
790 | // GracefulClose sets the state to draining, which prevents new streams from | ||
791 | // being created and causes the transport to be closed when the last active | ||
792 | // stream is closed. If there are no active streams, the transport is closed | ||
793 | // immediately. This does nothing if the transport is already draining or | ||
794 | // closing. | ||
795 | func (t *http2Client) GracefulClose() error { | ||
796 | t.mu.Lock() | ||
797 | // Make sure we move to draining only from active. | ||
798 | if t.state == draining || t.state == closing { | ||
799 | t.mu.Unlock() | ||
800 | return nil | ||
801 | } | ||
802 | t.state = draining | ||
803 | active := len(t.activeStreams) | ||
804 | t.mu.Unlock() | ||
805 | if active == 0 { | ||
806 | return t.Close() | ||
807 | } | ||
808 | t.controlBuf.put(&incomingGoAway{}) | ||
809 | return nil | ||
810 | } | ||
811 | |||
812 | // Write formats the data into HTTP2 data frame(s) and sends it out. The caller | ||
813 | // should proceed only if Write returns nil. | ||
814 | func (t *http2Client) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { | ||
815 | if opts.Last { | ||
816 | // If it's the last message, update stream state. | ||
817 | if !s.compareAndSwapState(streamActive, streamWriteDone) { | ||
818 | return errStreamDone | ||
819 | } | ||
820 | } else if s.getState() != streamActive { | ||
821 | return errStreamDone | ||
822 | } | ||
823 | df := &dataFrame{ | ||
824 | streamID: s.id, | ||
825 | endStream: opts.Last, | ||
826 | } | ||
827 | if hdr != nil || data != nil { // If it's not an empty data frame. | ||
828 | // Add some data to grpc message header so that we can equally | ||
829 | // distribute bytes across frames. | ||
830 | emptyLen := http2MaxFrameLen - len(hdr) | ||
831 | if emptyLen > len(data) { | ||
832 | emptyLen = len(data) | ||
833 | } | ||
834 | hdr = append(hdr, data[:emptyLen]...) | ||
835 | data = data[emptyLen:] | ||
836 | df.h, df.d = hdr, data | ||
837 | // TODO(mmukhi): The above logic in this if can be moved to loopyWriter's data handler. | ||
838 | if err := s.wq.get(int32(len(hdr) + len(data))); err != nil { | ||
839 | return err | ||
840 | } | ||
841 | } | ||
842 | return t.controlBuf.put(df) | ||
843 | } | ||
844 | |||
845 | func (t *http2Client) getStream(f http2.Frame) (*Stream, bool) { | ||
846 | t.mu.Lock() | ||
847 | defer t.mu.Unlock() | ||
848 | s, ok := t.activeStreams[f.Header().StreamID] | ||
849 | return s, ok | ||
850 | } | ||
851 | |||
852 | // adjustWindow sends out extra window update over the initial window size | ||
853 | // of stream if the application is requesting data larger in size than | ||
854 | // the window. | ||
855 | func (t *http2Client) adjustWindow(s *Stream, n uint32) { | ||
856 | if w := s.fc.maybeAdjust(n); w > 0 { | ||
857 | t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, increment: w}) | ||
858 | } | ||
859 | } | ||
860 | |||
861 | // updateWindow adjusts the inbound quota for the stream. | ||
862 | // Window updates will be sent out when the cumulative quota | ||
863 | // exceeds the corresponding threshold. | ||
864 | func (t *http2Client) updateWindow(s *Stream, n uint32) { | ||
865 | if w := s.fc.onRead(n); w > 0 { | ||
866 | t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, increment: w}) | ||
867 | } | ||
868 | } | ||
869 | |||
870 | // updateFlowControl updates the incoming flow control windows | ||
871 | // for the transport and the stream based on the current bdp | ||
872 | // estimation. | ||
873 | func (t *http2Client) updateFlowControl(n uint32) { | ||
874 | t.mu.Lock() | ||
875 | for _, s := range t.activeStreams { | ||
876 | s.fc.newLimit(n) | ||
877 | } | ||
878 | t.mu.Unlock() | ||
879 | updateIWS := func(interface{}) bool { | ||
880 | t.initialWindowSize = int32(n) | ||
881 | return true | ||
882 | } | ||
883 | t.controlBuf.executeAndPut(updateIWS, &outgoingWindowUpdate{streamID: 0, increment: t.fc.newLimit(n)}) | ||
884 | t.controlBuf.put(&outgoingSettings{ | ||
885 | ss: []http2.Setting{ | ||
886 | { | ||
887 | ID: http2.SettingInitialWindowSize, | ||
888 | Val: n, | ||
889 | }, | ||
890 | }, | ||
891 | }) | ||
892 | } | ||
893 | |||
894 | func (t *http2Client) handleData(f *http2.DataFrame) { | ||
895 | size := f.Header().Length | ||
896 | var sendBDPPing bool | ||
897 | if t.bdpEst != nil { | ||
898 | sendBDPPing = t.bdpEst.add(size) | ||
899 | } | ||
900 | // Decouple connection's flow control from application's read. | ||
901 | // An update on connection's flow control should not depend on | ||
902 | // whether user application has read the data or not. Such a | ||
903 | // restriction is already imposed on the stream's flow control, | ||
904 | // and therefore the sender will be blocked anyways. | ||
905 | // Decoupling the connection flow control will prevent other | ||
906 | // active(fast) streams from starving in presence of slow or | ||
907 | // inactive streams. | ||
908 | // | ||
909 | if w := t.fc.onData(size); w > 0 { | ||
910 | t.controlBuf.put(&outgoingWindowUpdate{ | ||
911 | streamID: 0, | ||
912 | increment: w, | ||
913 | }) | ||
914 | } | ||
915 | if sendBDPPing { | ||
916 | // Avoid excessive ping detection (e.g. in an L7 proxy) | ||
917 | // by sending a window update prior to the BDP ping. | ||
918 | |||
919 | if w := t.fc.reset(); w > 0 { | ||
920 | t.controlBuf.put(&outgoingWindowUpdate{ | ||
921 | streamID: 0, | ||
922 | increment: w, | ||
923 | }) | ||
924 | } | ||
925 | |||
926 | t.controlBuf.put(bdpPing) | ||
927 | } | ||
928 | // Select the right stream to dispatch. | ||
929 | s, ok := t.getStream(f) | ||
930 | if !ok { | ||
931 | return | ||
932 | } | ||
933 | if size > 0 { | ||
934 | if err := s.fc.onData(size); err != nil { | ||
935 | t.closeStream(s, io.EOF, true, http2.ErrCodeFlowControl, status.New(codes.Internal, err.Error()), nil, false) | ||
936 | return | ||
937 | } | ||
938 | if f.Header().Flags.Has(http2.FlagDataPadded) { | ||
939 | if w := s.fc.onRead(size - uint32(len(f.Data()))); w > 0 { | ||
940 | t.controlBuf.put(&outgoingWindowUpdate{s.id, w}) | ||
941 | } | ||
942 | } | ||
943 | // TODO(bradfitz, zhaoq): A copy is required here because there is no | ||
944 | // guarantee f.Data() is consumed before the arrival of next frame. | ||
945 | // Can this copy be eliminated? | ||
946 | if len(f.Data()) > 0 { | ||
947 | data := make([]byte, len(f.Data())) | ||
948 | copy(data, f.Data()) | ||
949 | s.write(recvMsg{data: data}) | ||
950 | } | ||
951 | } | ||
952 | // The server has closed the stream without sending trailers. Record that | ||
953 | // the read direction is closed, and set the status appropriately. | ||
954 | if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) { | ||
955 | t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.New(codes.Internal, "server closed the stream without sending trailers"), nil, true) | ||
956 | } | ||
957 | } | ||
958 | |||
959 | func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) { | ||
960 | s, ok := t.getStream(f) | ||
961 | if !ok { | ||
962 | return | ||
963 | } | ||
964 | if f.ErrCode == http2.ErrCodeRefusedStream { | ||
965 | // The stream was unprocessed by the server. | ||
966 | atomic.StoreUint32(&s.unprocessed, 1) | ||
967 | } | ||
968 | statusCode, ok := http2ErrConvTab[f.ErrCode] | ||
969 | if !ok { | ||
970 | warningf("transport: http2Client.handleRSTStream found no mapped gRPC status for the received http2 error %v", f.ErrCode) | ||
971 | statusCode = codes.Unknown | ||
972 | } | ||
973 | if statusCode == codes.Canceled { | ||
974 | // Our deadline was already exceeded, and that was likely the cause of | ||
975 | // this cancelation. Alter the status code accordingly. | ||
976 | if d, ok := s.ctx.Deadline(); ok && d.After(time.Now()) { | ||
977 | statusCode = codes.DeadlineExceeded | ||
978 | } | ||
979 | } | ||
980 | t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.Newf(statusCode, "stream terminated by RST_STREAM with error code: %v", f.ErrCode), nil, false) | ||
981 | } | ||
982 | |||
983 | func (t *http2Client) handleSettings(f *http2.SettingsFrame, isFirst bool) { | ||
984 | if f.IsAck() { | ||
985 | return | ||
986 | } | ||
987 | var maxStreams *uint32 | ||
988 | var ss []http2.Setting | ||
989 | var updateFuncs []func() | ||
990 | f.ForeachSetting(func(s http2.Setting) error { | ||
991 | switch s.ID { | ||
992 | case http2.SettingMaxConcurrentStreams: | ||
993 | maxStreams = new(uint32) | ||
994 | *maxStreams = s.Val | ||
995 | case http2.SettingMaxHeaderListSize: | ||
996 | updateFuncs = append(updateFuncs, func() { | ||
997 | t.maxSendHeaderListSize = new(uint32) | ||
998 | *t.maxSendHeaderListSize = s.Val | ||
999 | }) | ||
1000 | default: | ||
1001 | ss = append(ss, s) | ||
1002 | } | ||
1003 | return nil | ||
1004 | }) | ||
1005 | if isFirst && maxStreams == nil { | ||
1006 | maxStreams = new(uint32) | ||
1007 | *maxStreams = math.MaxUint32 | ||
1008 | } | ||
1009 | sf := &incomingSettings{ | ||
1010 | ss: ss, | ||
1011 | } | ||
1012 | if maxStreams != nil { | ||
1013 | updateStreamQuota := func() { | ||
1014 | delta := int64(*maxStreams) - int64(t.maxConcurrentStreams) | ||
1015 | t.maxConcurrentStreams = *maxStreams | ||
1016 | t.streamQuota += delta | ||
1017 | if delta > 0 && t.waitingStreams > 0 { | ||
1018 | close(t.streamsQuotaAvailable) // wake all of them up. | ||
1019 | t.streamsQuotaAvailable = make(chan struct{}, 1) | ||
1020 | } | ||
1021 | } | ||
1022 | updateFuncs = append(updateFuncs, updateStreamQuota) | ||
1023 | } | ||
1024 | t.controlBuf.executeAndPut(func(interface{}) bool { | ||
1025 | for _, f := range updateFuncs { | ||
1026 | f() | ||
1027 | } | ||
1028 | return true | ||
1029 | }, sf) | ||
1030 | } | ||
1031 | |||
1032 | func (t *http2Client) handlePing(f *http2.PingFrame) { | ||
1033 | if f.IsAck() { | ||
1034 | // Maybe it's a BDP ping. | ||
1035 | if t.bdpEst != nil { | ||
1036 | t.bdpEst.calculate(f.Data) | ||
1037 | } | ||
1038 | return | ||
1039 | } | ||
1040 | pingAck := &ping{ack: true} | ||
1041 | copy(pingAck.data[:], f.Data[:]) | ||
1042 | t.controlBuf.put(pingAck) | ||
1043 | } | ||
1044 | |||
1045 | func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { | ||
1046 | t.mu.Lock() | ||
1047 | if t.state == closing { | ||
1048 | t.mu.Unlock() | ||
1049 | return | ||
1050 | } | ||
1051 | if f.ErrCode == http2.ErrCodeEnhanceYourCalm { | ||
1052 | infof("Client received GoAway with http2.ErrCodeEnhanceYourCalm.") | ||
1053 | } | ||
1054 | id := f.LastStreamID | ||
1055 | if id > 0 && id%2 != 1 { | ||
1056 | t.mu.Unlock() | ||
1057 | t.Close() | ||
1058 | return | ||
1059 | } | ||
1060 | // A client can receive multiple GoAways from the server (see | ||
1061 | // https://github.com/grpc/grpc-go/issues/1387). The idea is that the first | ||
1062 | // GoAway will be sent with an ID of MaxInt32 and the second GoAway will be | ||
1063 | // sent after an RTT delay with the ID of the last stream the server will | ||
1064 | // process. | ||
1065 | // | ||
1066 | // Therefore, when we get the first GoAway we don't necessarily close any | ||
1067 | // streams. While in case of second GoAway we close all streams created after | ||
1068 | // the GoAwayId. This way streams that were in-flight while the GoAway from | ||
1069 | // server was being sent don't get killed. | ||
1070 | select { | ||
1071 | case <-t.goAway: // t.goAway has been closed (i.e.,multiple GoAways). | ||
1072 | // If there are multiple GoAways the first one should always have an ID greater than the following ones. | ||
1073 | if id > t.prevGoAwayID { | ||
1074 | t.mu.Unlock() | ||
1075 | t.Close() | ||
1076 | return | ||
1077 | } | ||
1078 | default: | ||
1079 | t.setGoAwayReason(f) | ||
1080 | close(t.goAway) | ||
1081 | t.state = draining | ||
1082 | t.controlBuf.put(&incomingGoAway{}) | ||
1083 | |||
1084 | // This has to be a new goroutine because we're still using the current goroutine to read in the transport. | ||
1085 | t.onGoAway(t.goAwayReason) | ||
1086 | } | ||
1087 | // All streams with IDs greater than the GoAwayId | ||
1088 | // and smaller than the previous GoAway ID should be killed. | ||
1089 | upperLimit := t.prevGoAwayID | ||
1090 | if upperLimit == 0 { // This is the first GoAway Frame. | ||
1091 | upperLimit = math.MaxUint32 // Kill all streams after the GoAway ID. | ||
1092 | } | ||
1093 | for streamID, stream := range t.activeStreams { | ||
1094 | if streamID > id && streamID <= upperLimit { | ||
1095 | // The stream was unprocessed by the server. | ||
1096 | atomic.StoreUint32(&stream.unprocessed, 1) | ||
1097 | t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false) | ||
1098 | } | ||
1099 | } | ||
1100 | t.prevGoAwayID = id | ||
1101 | active := len(t.activeStreams) | ||
1102 | t.mu.Unlock() | ||
1103 | if active == 0 { | ||
1104 | t.Close() | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | // setGoAwayReason sets the value of t.goAwayReason based | ||
1109 | // on the GoAway frame received. | ||
1110 | // It expects a lock on transport's mutext to be held by | ||
1111 | // the caller. | ||
1112 | func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) { | ||
1113 | t.goAwayReason = GoAwayNoReason | ||
1114 | switch f.ErrCode { | ||
1115 | case http2.ErrCodeEnhanceYourCalm: | ||
1116 | if string(f.DebugData()) == "too_many_pings" { | ||
1117 | t.goAwayReason = GoAwayTooManyPings | ||
1118 | } | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | func (t *http2Client) GetGoAwayReason() GoAwayReason { | ||
1123 | t.mu.Lock() | ||
1124 | defer t.mu.Unlock() | ||
1125 | return t.goAwayReason | ||
1126 | } | ||
1127 | |||
1128 | func (t *http2Client) handleWindowUpdate(f *http2.WindowUpdateFrame) { | ||
1129 | t.controlBuf.put(&incomingWindowUpdate{ | ||
1130 | streamID: f.Header().StreamID, | ||
1131 | increment: f.Increment, | ||
1132 | }) | ||
1133 | } | ||
1134 | |||
1135 | // operateHeaders takes action on the decoded headers. | ||
1136 | func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { | ||
1137 | s, ok := t.getStream(frame) | ||
1138 | if !ok { | ||
1139 | return | ||
1140 | } | ||
1141 | atomic.StoreUint32(&s.bytesReceived, 1) | ||
1142 | var state decodeState | ||
1143 | if err := state.decodeHeader(frame); err != nil { | ||
1144 | t.closeStream(s, err, true, http2.ErrCodeProtocol, status.New(codes.Internal, err.Error()), nil, false) | ||
1145 | // Something wrong. Stops reading even when there is remaining. | ||
1146 | return | ||
1147 | } | ||
1148 | |||
1149 | endStream := frame.StreamEnded() | ||
1150 | var isHeader bool | ||
1151 | defer func() { | ||
1152 | if t.statsHandler != nil { | ||
1153 | if isHeader { | ||
1154 | inHeader := &stats.InHeader{ | ||
1155 | Client: true, | ||
1156 | WireLength: int(frame.Header().Length), | ||
1157 | } | ||
1158 | t.statsHandler.HandleRPC(s.ctx, inHeader) | ||
1159 | } else { | ||
1160 | inTrailer := &stats.InTrailer{ | ||
1161 | Client: true, | ||
1162 | WireLength: int(frame.Header().Length), | ||
1163 | } | ||
1164 | t.statsHandler.HandleRPC(s.ctx, inTrailer) | ||
1165 | } | ||
1166 | } | ||
1167 | }() | ||
1168 | // If headers haven't been received yet. | ||
1169 | if atomic.SwapUint32(&s.headerDone, 1) == 0 { | ||
1170 | if !endStream { | ||
1171 | // Headers frame is not actually a trailers-only frame. | ||
1172 | isHeader = true | ||
1173 | // These values can be set without any synchronization because | ||
1174 | // stream goroutine will read it only after seeing a closed | ||
1175 | // headerChan which we'll close after setting this. | ||
1176 | s.recvCompress = state.encoding | ||
1177 | if len(state.mdata) > 0 { | ||
1178 | s.header = state.mdata | ||
1179 | } | ||
1180 | } else { | ||
1181 | s.noHeaders = true | ||
1182 | } | ||
1183 | close(s.headerChan) | ||
1184 | } | ||
1185 | if !endStream { | ||
1186 | return | ||
1187 | } | ||
1188 | // if client received END_STREAM from server while stream was still active, send RST_STREAM | ||
1189 | rst := s.getState() == streamActive | ||
1190 | t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, state.status(), state.mdata, true) | ||
1191 | } | ||
1192 | |||
1193 | // reader runs as a separate goroutine in charge of reading data from network | ||
1194 | // connection. | ||
1195 | // | ||
1196 | // TODO(zhaoq): currently one reader per transport. Investigate whether this is | ||
1197 | // optimal. | ||
1198 | // TODO(zhaoq): Check the validity of the incoming frame sequence. | ||
1199 | func (t *http2Client) reader() { | ||
1200 | defer close(t.readerDone) | ||
1201 | // Check the validity of server preface. | ||
1202 | frame, err := t.framer.fr.ReadFrame() | ||
1203 | if err != nil { | ||
1204 | t.Close() // this kicks off resetTransport, so must be last before return | ||
1205 | return | ||
1206 | } | ||
1207 | t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!) | ||
1208 | if t.keepaliveEnabled { | ||
1209 | atomic.CompareAndSwapUint32(&t.activity, 0, 1) | ||
1210 | } | ||
1211 | sf, ok := frame.(*http2.SettingsFrame) | ||
1212 | if !ok { | ||
1213 | t.Close() // this kicks off resetTransport, so must be last before return | ||
1214 | return | ||
1215 | } | ||
1216 | t.onPrefaceReceipt() | ||
1217 | t.handleSettings(sf, true) | ||
1218 | |||
1219 | // loop to keep reading incoming messages on this transport. | ||
1220 | for { | ||
1221 | frame, err := t.framer.fr.ReadFrame() | ||
1222 | if t.keepaliveEnabled { | ||
1223 | atomic.CompareAndSwapUint32(&t.activity, 0, 1) | ||
1224 | } | ||
1225 | if err != nil { | ||
1226 | // Abort an active stream if the http2.Framer returns a | ||
1227 | // http2.StreamError. This can happen only if the server's response | ||
1228 | // is malformed http2. | ||
1229 | if se, ok := err.(http2.StreamError); ok { | ||
1230 | t.mu.Lock() | ||
1231 | s := t.activeStreams[se.StreamID] | ||
1232 | t.mu.Unlock() | ||
1233 | if s != nil { | ||
1234 | // use error detail to provide better err message | ||
1235 | code := http2ErrConvTab[se.Code] | ||
1236 | msg := t.framer.fr.ErrorDetail().Error() | ||
1237 | t.closeStream(s, status.Error(code, msg), true, http2.ErrCodeProtocol, status.New(code, msg), nil, false) | ||
1238 | } | ||
1239 | continue | ||
1240 | } else { | ||
1241 | // Transport error. | ||
1242 | t.Close() | ||
1243 | return | ||
1244 | } | ||
1245 | } | ||
1246 | switch frame := frame.(type) { | ||
1247 | case *http2.MetaHeadersFrame: | ||
1248 | t.operateHeaders(frame) | ||
1249 | case *http2.DataFrame: | ||
1250 | t.handleData(frame) | ||
1251 | case *http2.RSTStreamFrame: | ||
1252 | t.handleRSTStream(frame) | ||
1253 | case *http2.SettingsFrame: | ||
1254 | t.handleSettings(frame, false) | ||
1255 | case *http2.PingFrame: | ||
1256 | t.handlePing(frame) | ||
1257 | case *http2.GoAwayFrame: | ||
1258 | t.handleGoAway(frame) | ||
1259 | case *http2.WindowUpdateFrame: | ||
1260 | t.handleWindowUpdate(frame) | ||
1261 | default: | ||
1262 | errorf("transport: http2Client.reader got unhandled frame type %v.", frame) | ||
1263 | } | ||
1264 | } | ||
1265 | } | ||
1266 | |||
1267 | // keepalive running in a separate goroutune makes sure the connection is alive by sending pings. | ||
1268 | func (t *http2Client) keepalive() { | ||
1269 | p := &ping{data: [8]byte{}} | ||
1270 | timer := time.NewTimer(t.kp.Time) | ||
1271 | for { | ||
1272 | select { | ||
1273 | case <-timer.C: | ||
1274 | if atomic.CompareAndSwapUint32(&t.activity, 1, 0) { | ||
1275 | timer.Reset(t.kp.Time) | ||
1276 | continue | ||
1277 | } | ||
1278 | // Check if keepalive should go dormant. | ||
1279 | t.mu.Lock() | ||
1280 | if len(t.activeStreams) < 1 && !t.kp.PermitWithoutStream { | ||
1281 | // Make awakenKeepalive writable. | ||
1282 | <-t.awakenKeepalive | ||
1283 | t.mu.Unlock() | ||
1284 | select { | ||
1285 | case <-t.awakenKeepalive: | ||
1286 | // If the control gets here a ping has been sent | ||
1287 | // need to reset the timer with keepalive.Timeout. | ||
1288 | case <-t.ctx.Done(): | ||
1289 | return | ||
1290 | } | ||
1291 | } else { | ||
1292 | t.mu.Unlock() | ||
1293 | if channelz.IsOn() { | ||
1294 | atomic.AddInt64(&t.czData.kpCount, 1) | ||
1295 | } | ||
1296 | // Send ping. | ||
1297 | t.controlBuf.put(p) | ||
1298 | } | ||
1299 | |||
1300 | // By the time control gets here a ping has been sent one way or the other. | ||
1301 | timer.Reset(t.kp.Timeout) | ||
1302 | select { | ||
1303 | case <-timer.C: | ||
1304 | if atomic.CompareAndSwapUint32(&t.activity, 1, 0) { | ||
1305 | timer.Reset(t.kp.Time) | ||
1306 | continue | ||
1307 | } | ||
1308 | t.Close() | ||
1309 | return | ||
1310 | case <-t.ctx.Done(): | ||
1311 | if !timer.Stop() { | ||
1312 | <-timer.C | ||
1313 | } | ||
1314 | return | ||
1315 | } | ||
1316 | case <-t.ctx.Done(): | ||
1317 | if !timer.Stop() { | ||
1318 | <-timer.C | ||
1319 | } | ||
1320 | return | ||
1321 | } | ||
1322 | } | ||
1323 | } | ||
1324 | |||
1325 | func (t *http2Client) Error() <-chan struct{} { | ||
1326 | return t.ctx.Done() | ||
1327 | } | ||
1328 | |||
1329 | func (t *http2Client) GoAway() <-chan struct{} { | ||
1330 | return t.goAway | ||
1331 | } | ||
1332 | |||
1333 | func (t *http2Client) ChannelzMetric() *channelz.SocketInternalMetric { | ||
1334 | s := channelz.SocketInternalMetric{ | ||
1335 | StreamsStarted: atomic.LoadInt64(&t.czData.streamsStarted), | ||
1336 | StreamsSucceeded: atomic.LoadInt64(&t.czData.streamsSucceeded), | ||
1337 | StreamsFailed: atomic.LoadInt64(&t.czData.streamsFailed), | ||
1338 | MessagesSent: atomic.LoadInt64(&t.czData.msgSent), | ||
1339 | MessagesReceived: atomic.LoadInt64(&t.czData.msgRecv), | ||
1340 | KeepAlivesSent: atomic.LoadInt64(&t.czData.kpCount), | ||
1341 | LastLocalStreamCreatedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastStreamCreatedTime)), | ||
1342 | LastMessageSentTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgSentTime)), | ||
1343 | LastMessageReceivedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgRecvTime)), | ||
1344 | LocalFlowControlWindow: int64(t.fc.getSize()), | ||
1345 | SocketOptions: channelz.GetSocketOption(t.conn), | ||
1346 | LocalAddr: t.localAddr, | ||
1347 | RemoteAddr: t.remoteAddr, | ||
1348 | // RemoteName : | ||
1349 | } | ||
1350 | if au, ok := t.authInfo.(credentials.ChannelzSecurityInfo); ok { | ||
1351 | s.Security = au.GetSecurityValue() | ||
1352 | } | ||
1353 | s.RemoteFlowControlWindow = t.getOutFlowWindow() | ||
1354 | return &s | ||
1355 | } | ||
1356 | |||
1357 | func (t *http2Client) IncrMsgSent() { | ||
1358 | atomic.AddInt64(&t.czData.msgSent, 1) | ||
1359 | atomic.StoreInt64(&t.czData.lastMsgSentTime, time.Now().UnixNano()) | ||
1360 | } | ||
1361 | |||
1362 | func (t *http2Client) IncrMsgRecv() { | ||
1363 | atomic.AddInt64(&t.czData.msgRecv, 1) | ||
1364 | atomic.StoreInt64(&t.czData.lastMsgRecvTime, time.Now().UnixNano()) | ||
1365 | } | ||
1366 | |||
1367 | func (t *http2Client) getOutFlowWindow() int64 { | ||
1368 | resp := make(chan uint32, 1) | ||
1369 | timer := time.NewTimer(time.Second) | ||
1370 | defer timer.Stop() | ||
1371 | t.controlBuf.put(&outFlowControlSizeRequest{resp}) | ||
1372 | select { | ||
1373 | case sz := <-resp: | ||
1374 | return int64(sz) | ||
1375 | case <-t.ctxDone: | ||
1376 | return -1 | ||
1377 | case <-timer.C: | ||
1378 | return -2 | ||
1379 | } | ||
1380 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index b6f93e3..df27403 100644 --- a/vendor/google.golang.org/grpc/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go | |||
@@ -20,10 +20,11 @@ package transport | |||
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "bytes" |
23 | "context" | ||
23 | "errors" | 24 | "errors" |
25 | "fmt" | ||
24 | "io" | 26 | "io" |
25 | "math" | 27 | "math" |
26 | "math/rand" | ||
27 | "net" | 28 | "net" |
28 | "strconv" | 29 | "strconv" |
29 | "sync" | 30 | "sync" |
@@ -31,11 +32,14 @@ import ( | |||
31 | "time" | 32 | "time" |
32 | 33 | ||
33 | "github.com/golang/protobuf/proto" | 34 | "github.com/golang/protobuf/proto" |
34 | "golang.org/x/net/context" | ||
35 | "golang.org/x/net/http2" | 35 | "golang.org/x/net/http2" |
36 | "golang.org/x/net/http2/hpack" | 36 | "golang.org/x/net/http2/hpack" |
37 | |||
37 | "google.golang.org/grpc/codes" | 38 | "google.golang.org/grpc/codes" |
38 | "google.golang.org/grpc/credentials" | 39 | "google.golang.org/grpc/credentials" |
40 | "google.golang.org/grpc/grpclog" | ||
41 | "google.golang.org/grpc/internal/channelz" | ||
42 | "google.golang.org/grpc/internal/grpcrand" | ||
39 | "google.golang.org/grpc/keepalive" | 43 | "google.golang.org/grpc/keepalive" |
40 | "google.golang.org/grpc/metadata" | 44 | "google.golang.org/grpc/metadata" |
41 | "google.golang.org/grpc/peer" | 45 | "google.golang.org/grpc/peer" |
@@ -44,39 +48,37 @@ import ( | |||
44 | "google.golang.org/grpc/tap" | 48 | "google.golang.org/grpc/tap" |
45 | ) | 49 | ) |
46 | 50 | ||
47 | // ErrIllegalHeaderWrite indicates that setting header is illegal because of | 51 | var ( |
48 | // the stream's state. | 52 | // ErrIllegalHeaderWrite indicates that setting header is illegal because of |
49 | var ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") | 53 | // the stream's state. |
54 | ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") | ||
55 | // ErrHeaderListSizeLimitViolation indicates that the header list size is larger | ||
56 | // than the limit set by peer. | ||
57 | ErrHeaderListSizeLimitViolation = errors.New("transport: trying to send header list size larger than the limit set by peer") | ||
58 | ) | ||
50 | 59 | ||
51 | // http2Server implements the ServerTransport interface with HTTP2. | 60 | // http2Server implements the ServerTransport interface with HTTP2. |
52 | type http2Server struct { | 61 | type http2Server struct { |
53 | ctx context.Context | 62 | ctx context.Context |
63 | ctxDone <-chan struct{} // Cache the context.Done() chan | ||
64 | cancel context.CancelFunc | ||
54 | conn net.Conn | 65 | conn net.Conn |
66 | loopy *loopyWriter | ||
67 | readerDone chan struct{} // sync point to enable testing. | ||
68 | writerDone chan struct{} // sync point to enable testing. | ||
55 | remoteAddr net.Addr | 69 | remoteAddr net.Addr |
56 | localAddr net.Addr | 70 | localAddr net.Addr |
57 | maxStreamID uint32 // max stream ID ever seen | 71 | maxStreamID uint32 // max stream ID ever seen |
58 | authInfo credentials.AuthInfo // auth info about the connection | 72 | authInfo credentials.AuthInfo // auth info about the connection |
59 | inTapHandle tap.ServerInHandle | 73 | inTapHandle tap.ServerInHandle |
60 | // writableChan synchronizes write access to the transport. | 74 | framer *framer |
61 | // A writer acquires the write lock by receiving a value on writableChan | ||
62 | // and releases it by sending on writableChan. | ||
63 | writableChan chan int | ||
64 | // shutdownChan is closed when Close is called. | ||
65 | // Blocking operations should select on shutdownChan to avoid | ||
66 | // blocking forever after Close. | ||
67 | shutdownChan chan struct{} | ||
68 | framer *framer | ||
69 | hBuf *bytes.Buffer // the buffer for HPACK encoding | ||
70 | hEnc *hpack.Encoder // HPACK encoder | ||
71 | // The max number of concurrent streams. | 75 | // The max number of concurrent streams. |
72 | maxStreams uint32 | 76 | maxStreams uint32 |
73 | // controlBuf delivers all the control related tasks (e.g., window | 77 | // controlBuf delivers all the control related tasks (e.g., window |
74 | // updates, reset streams, and various settings) to the controller. | 78 | // updates, reset streams, and various settings) to the controller. |
75 | controlBuf *controlBuffer | 79 | controlBuf *controlBuffer |
76 | fc *inFlow | 80 | fc *trInFlow |
77 | // sendQuotaPool provides flow control to outbound message. | 81 | stats stats.Handler |
78 | sendQuotaPool *quotaPool | ||
79 | stats stats.Handler | ||
80 | // Flag to keep track of reading activity on transport. | 82 | // Flag to keep track of reading activity on transport. |
81 | // 1 is true and 0 is false. | 83 | // 1 is true and 0 is false. |
82 | activity uint32 // Accessed atomically. | 84 | activity uint32 // Accessed atomically. |
@@ -92,11 +94,10 @@ type http2Server struct { | |||
92 | // Flag to signify that number of ping strikes should be reset to 0. | 94 | // Flag to signify that number of ping strikes should be reset to 0. |
93 | // This is set whenever data or header frames are sent. | 95 | // This is set whenever data or header frames are sent. |
94 | // 1 means yes. | 96 | // 1 means yes. |
95 | resetPingStrikes uint32 // Accessed atomically. | 97 | resetPingStrikes uint32 // Accessed atomically. |
96 | initialWindowSize int32 | 98 | initialWindowSize int32 |
97 | bdpEst *bdpEstimator | 99 | bdpEst *bdpEstimator |
98 | 100 | maxSendHeaderListSize *uint32 | |
99 | outQuotaVersion uint32 | ||
100 | 101 | ||
101 | mu sync.Mutex // guard the following | 102 | mu sync.Mutex // guard the following |
102 | 103 | ||
@@ -109,19 +110,27 @@ type http2Server struct { | |||
109 | drainChan chan struct{} | 110 | drainChan chan struct{} |
110 | state transportState | 111 | state transportState |
111 | activeStreams map[uint32]*Stream | 112 | activeStreams map[uint32]*Stream |
112 | // the per-stream outbound flow control window size set by the peer. | ||
113 | streamSendQuota uint32 | ||
114 | // idle is the time instant when the connection went idle. | 113 | // idle is the time instant when the connection went idle. |
115 | // This is either the begining of the connection or when the number of | 114 | // This is either the beginning of the connection or when the number of |
116 | // RPCs go down to 0. | 115 | // RPCs go down to 0. |
117 | // When the connection is busy, this value is set to 0. | 116 | // When the connection is busy, this value is set to 0. |
118 | idle time.Time | 117 | idle time.Time |
118 | |||
119 | // Fields below are for channelz metric collection. | ||
120 | channelzID int64 // channelz unique identification number | ||
121 | czData *channelzData | ||
119 | } | 122 | } |
120 | 123 | ||
121 | // newHTTP2Server constructs a ServerTransport based on HTTP2. ConnectionError is | 124 | // newHTTP2Server constructs a ServerTransport based on HTTP2. ConnectionError is |
122 | // returned if something goes wrong. | 125 | // returned if something goes wrong. |
123 | func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { | 126 | func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { |
124 | framer := newFramer(conn) | 127 | writeBufSize := config.WriteBufferSize |
128 | readBufSize := config.ReadBufferSize | ||
129 | maxHeaderListSize := defaultServerMaxHeaderListSize | ||
130 | if config.MaxHeaderListSize != nil { | ||
131 | maxHeaderListSize = *config.MaxHeaderListSize | ||
132 | } | ||
133 | framer := newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize) | ||
125 | // Send initial settings as connection preface to client. | 134 | // Send initial settings as connection preface to client. |
126 | var isettings []http2.Setting | 135 | var isettings []http2.Setting |
127 | // TODO(zhaoq): Have a better way to signal "no limit" because 0 is | 136 | // TODO(zhaoq): Have a better way to signal "no limit" because 0 is |
@@ -151,13 +160,19 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err | |||
151 | ID: http2.SettingInitialWindowSize, | 160 | ID: http2.SettingInitialWindowSize, |
152 | Val: uint32(iwz)}) | 161 | Val: uint32(iwz)}) |
153 | } | 162 | } |
154 | if err := framer.writeSettings(true, isettings...); err != nil { | 163 | if config.MaxHeaderListSize != nil { |
155 | return nil, connectionErrorf(true, err, "transport: %v", err) | 164 | isettings = append(isettings, http2.Setting{ |
165 | ID: http2.SettingMaxHeaderListSize, | ||
166 | Val: *config.MaxHeaderListSize, | ||
167 | }) | ||
168 | } | ||
169 | if err := framer.fr.WriteSettings(isettings...); err != nil { | ||
170 | return nil, connectionErrorf(false, err, "transport: %v", err) | ||
156 | } | 171 | } |
157 | // Adjust the connection flow control window if needed. | 172 | // Adjust the connection flow control window if needed. |
158 | if delta := uint32(icwz - defaultWindowSize); delta > 0 { | 173 | if delta := uint32(icwz - defaultWindowSize); delta > 0 { |
159 | if err := framer.writeWindowUpdate(true, 0, delta); err != nil { | 174 | if err := framer.fr.WriteWindowUpdate(0, delta); err != nil { |
160 | return nil, connectionErrorf(true, err, "transport: %v", err) | 175 | return nil, connectionErrorf(false, err, "transport: %v", err) |
161 | } | 176 | } |
162 | } | 177 | } |
163 | kp := config.KeepaliveParams | 178 | kp := config.KeepaliveParams |
@@ -182,32 +197,31 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err | |||
182 | if kep.MinTime == 0 { | 197 | if kep.MinTime == 0 { |
183 | kep.MinTime = defaultKeepalivePolicyMinTime | 198 | kep.MinTime = defaultKeepalivePolicyMinTime |
184 | } | 199 | } |
185 | var buf bytes.Buffer | 200 | ctx, cancel := context.WithCancel(context.Background()) |
186 | t := &http2Server{ | 201 | t := &http2Server{ |
187 | ctx: context.Background(), | 202 | ctx: ctx, |
203 | cancel: cancel, | ||
204 | ctxDone: ctx.Done(), | ||
188 | conn: conn, | 205 | conn: conn, |
189 | remoteAddr: conn.RemoteAddr(), | 206 | remoteAddr: conn.RemoteAddr(), |
190 | localAddr: conn.LocalAddr(), | 207 | localAddr: conn.LocalAddr(), |
191 | authInfo: config.AuthInfo, | 208 | authInfo: config.AuthInfo, |
192 | framer: framer, | 209 | framer: framer, |
193 | hBuf: &buf, | 210 | readerDone: make(chan struct{}), |
194 | hEnc: hpack.NewEncoder(&buf), | 211 | writerDone: make(chan struct{}), |
195 | maxStreams: maxStreams, | 212 | maxStreams: maxStreams, |
196 | inTapHandle: config.InTapHandle, | 213 | inTapHandle: config.InTapHandle, |
197 | controlBuf: newControlBuffer(), | 214 | fc: &trInFlow{limit: uint32(icwz)}, |
198 | fc: &inFlow{limit: uint32(icwz)}, | ||
199 | sendQuotaPool: newQuotaPool(defaultWindowSize), | ||
200 | state: reachable, | 215 | state: reachable, |
201 | writableChan: make(chan int, 1), | ||
202 | shutdownChan: make(chan struct{}), | ||
203 | activeStreams: make(map[uint32]*Stream), | 216 | activeStreams: make(map[uint32]*Stream), |
204 | streamSendQuota: defaultWindowSize, | ||
205 | stats: config.StatsHandler, | 217 | stats: config.StatsHandler, |
206 | kp: kp, | 218 | kp: kp, |
207 | idle: time.Now(), | 219 | idle: time.Now(), |
208 | kep: kep, | 220 | kep: kep, |
209 | initialWindowSize: iwz, | 221 | initialWindowSize: iwz, |
222 | czData: new(channelzData), | ||
210 | } | 223 | } |
224 | t.controlBuf = newControlBuffer(t.ctxDone) | ||
211 | if dynamicWindow { | 225 | if dynamicWindow { |
212 | t.bdpEst = &bdpEstimator{ | 226 | t.bdpEst = &bdpEstimator{ |
213 | bdp: initialWindowSize, | 227 | bdp: initialWindowSize, |
@@ -222,37 +236,83 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err | |||
222 | connBegin := &stats.ConnBegin{} | 236 | connBegin := &stats.ConnBegin{} |
223 | t.stats.HandleConn(t.ctx, connBegin) | 237 | t.stats.HandleConn(t.ctx, connBegin) |
224 | } | 238 | } |
225 | go t.controller() | 239 | if channelz.IsOn() { |
240 | t.channelzID = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr)) | ||
241 | } | ||
242 | t.framer.writer.Flush() | ||
243 | |||
244 | defer func() { | ||
245 | if err != nil { | ||
246 | t.Close() | ||
247 | } | ||
248 | }() | ||
249 | |||
250 | // Check the validity of client preface. | ||
251 | preface := make([]byte, len(clientPreface)) | ||
252 | if _, err := io.ReadFull(t.conn, preface); err != nil { | ||
253 | return nil, connectionErrorf(false, err, "transport: http2Server.HandleStreams failed to receive the preface from client: %v", err) | ||
254 | } | ||
255 | if !bytes.Equal(preface, clientPreface) { | ||
256 | return nil, connectionErrorf(false, nil, "transport: http2Server.HandleStreams received bogus greeting from client: %q", preface) | ||
257 | } | ||
258 | |||
259 | frame, err := t.framer.fr.ReadFrame() | ||
260 | if err == io.EOF || err == io.ErrUnexpectedEOF { | ||
261 | return nil, err | ||
262 | } | ||
263 | if err != nil { | ||
264 | return nil, connectionErrorf(false, err, "transport: http2Server.HandleStreams failed to read initial settings frame: %v", err) | ||
265 | } | ||
266 | atomic.StoreUint32(&t.activity, 1) | ||
267 | sf, ok := frame.(*http2.SettingsFrame) | ||
268 | if !ok { | ||
269 | return nil, connectionErrorf(false, nil, "transport: http2Server.HandleStreams saw invalid preface type %T from client", frame) | ||
270 | } | ||
271 | t.handleSettings(sf) | ||
272 | |||
273 | go func() { | ||
274 | t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst) | ||
275 | t.loopy.ssGoAwayHandler = t.outgoingGoAwayHandler | ||
276 | if err := t.loopy.run(); err != nil { | ||
277 | errorf("transport: loopyWriter.run returning. Err: %v", err) | ||
278 | } | ||
279 | t.conn.Close() | ||
280 | close(t.writerDone) | ||
281 | }() | ||
226 | go t.keepalive() | 282 | go t.keepalive() |
227 | t.writableChan <- 0 | ||
228 | return t, nil | 283 | return t, nil |
229 | } | 284 | } |
230 | 285 | ||
231 | // operateHeader takes action on the decoded headers. | 286 | // operateHeader takes action on the decoded headers. |
232 | func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (close bool) { | 287 | func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (fatal bool) { |
233 | buf := newRecvBuffer() | 288 | streamID := frame.Header().StreamID |
234 | s := &Stream{ | 289 | state := decodeState{serverSide: true} |
235 | id: frame.Header().StreamID, | 290 | if err := state.decodeHeader(frame); err != nil { |
236 | st: t, | 291 | if se, ok := status.FromError(err); ok { |
237 | buf: buf, | 292 | t.controlBuf.put(&cleanupStream{ |
238 | fc: &inFlow{limit: uint32(t.initialWindowSize)}, | 293 | streamID: streamID, |
239 | } | 294 | rst: true, |
240 | 295 | rstCode: statusCodeConvTab[se.Code()], | |
241 | var state decodeState | 296 | onWrite: func() {}, |
242 | for _, hf := range frame.Fields { | 297 | }) |
243 | if err := state.processHeaderField(hf); err != nil { | ||
244 | if se, ok := err.(StreamError); ok { | ||
245 | t.controlBuf.put(&resetStream{s.id, statusCodeConvTab[se.Code]}) | ||
246 | } | ||
247 | return | ||
248 | } | 298 | } |
299 | return false | ||
249 | } | 300 | } |
250 | 301 | ||
302 | buf := newRecvBuffer() | ||
303 | s := &Stream{ | ||
304 | id: streamID, | ||
305 | st: t, | ||
306 | buf: buf, | ||
307 | fc: &inFlow{limit: uint32(t.initialWindowSize)}, | ||
308 | recvCompress: state.encoding, | ||
309 | method: state.method, | ||
310 | contentSubtype: state.contentSubtype, | ||
311 | } | ||
251 | if frame.StreamEnded() { | 312 | if frame.StreamEnded() { |
252 | // s is just created by the caller. No lock needed. | 313 | // s is just created by the caller. No lock needed. |
253 | s.state = streamReadDone | 314 | s.state = streamReadDone |
254 | } | 315 | } |
255 | s.recvCompress = state.encoding | ||
256 | if state.timeoutSet { | 316 | if state.timeoutSet { |
257 | s.ctx, s.cancel = context.WithTimeout(t.ctx, state.timeout) | 317 | s.ctx, s.cancel = context.WithTimeout(t.ctx, state.timeout) |
258 | } else { | 318 | } else { |
@@ -266,25 +326,16 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( | |||
266 | pr.AuthInfo = t.authInfo | 326 | pr.AuthInfo = t.authInfo |
267 | } | 327 | } |
268 | s.ctx = peer.NewContext(s.ctx, pr) | 328 | s.ctx = peer.NewContext(s.ctx, pr) |
269 | // Cache the current stream to the context so that the server application | ||
270 | // can find out. Required when the server wants to send some metadata | ||
271 | // back to the client (unary call only). | ||
272 | s.ctx = newContextWithStream(s.ctx, s) | ||
273 | // Attach the received metadata to the context. | 329 | // Attach the received metadata to the context. |
274 | if len(state.mdata) > 0 { | 330 | if len(state.mdata) > 0 { |
275 | s.ctx = metadata.NewIncomingContext(s.ctx, state.mdata) | 331 | s.ctx = metadata.NewIncomingContext(s.ctx, state.mdata) |
276 | } | 332 | } |
277 | s.trReader = &transportReader{ | 333 | if state.statsTags != nil { |
278 | reader: &recvBufferReader{ | 334 | s.ctx = stats.SetIncomingTags(s.ctx, state.statsTags) |
279 | ctx: s.ctx, | 335 | } |
280 | recv: s.buf, | 336 | if state.statsTrace != nil { |
281 | }, | 337 | s.ctx = stats.SetIncomingTrace(s.ctx, state.statsTrace) |
282 | windowHandler: func(n int) { | ||
283 | t.updateWindow(s, uint32(n)) | ||
284 | }, | ||
285 | } | 338 | } |
286 | s.recvCompress = state.encoding | ||
287 | s.method = state.method | ||
288 | if t.inTapHandle != nil { | 339 | if t.inTapHandle != nil { |
289 | var err error | 340 | var err error |
290 | info := &tap.Info{ | 341 | info := &tap.Info{ |
@@ -293,33 +344,46 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( | |||
293 | s.ctx, err = t.inTapHandle(s.ctx, info) | 344 | s.ctx, err = t.inTapHandle(s.ctx, info) |
294 | if err != nil { | 345 | if err != nil { |
295 | warningf("transport: http2Server.operateHeaders got an error from InTapHandle: %v", err) | 346 | warningf("transport: http2Server.operateHeaders got an error from InTapHandle: %v", err) |
296 | t.controlBuf.put(&resetStream{s.id, http2.ErrCodeRefusedStream}) | 347 | t.controlBuf.put(&cleanupStream{ |
297 | return | 348 | streamID: s.id, |
349 | rst: true, | ||
350 | rstCode: http2.ErrCodeRefusedStream, | ||
351 | onWrite: func() {}, | ||
352 | }) | ||
353 | return false | ||
298 | } | 354 | } |
299 | } | 355 | } |
300 | t.mu.Lock() | 356 | t.mu.Lock() |
301 | if t.state != reachable { | 357 | if t.state != reachable { |
302 | t.mu.Unlock() | 358 | t.mu.Unlock() |
303 | return | 359 | return false |
304 | } | 360 | } |
305 | if uint32(len(t.activeStreams)) >= t.maxStreams { | 361 | if uint32(len(t.activeStreams)) >= t.maxStreams { |
306 | t.mu.Unlock() | 362 | t.mu.Unlock() |
307 | t.controlBuf.put(&resetStream{s.id, http2.ErrCodeRefusedStream}) | 363 | t.controlBuf.put(&cleanupStream{ |
308 | return | 364 | streamID: streamID, |
365 | rst: true, | ||
366 | rstCode: http2.ErrCodeRefusedStream, | ||
367 | onWrite: func() {}, | ||
368 | }) | ||
369 | return false | ||
309 | } | 370 | } |
310 | if s.id%2 != 1 || s.id <= t.maxStreamID { | 371 | if streamID%2 != 1 || streamID <= t.maxStreamID { |
311 | t.mu.Unlock() | 372 | t.mu.Unlock() |
312 | // illegal gRPC stream id. | 373 | // illegal gRPC stream id. |
313 | errorf("transport: http2Server.HandleStreams received an illegal stream id: %v", s.id) | 374 | errorf("transport: http2Server.HandleStreams received an illegal stream id: %v", streamID) |
314 | return true | 375 | return true |
315 | } | 376 | } |
316 | t.maxStreamID = s.id | 377 | t.maxStreamID = streamID |
317 | s.sendQuotaPool = newQuotaPool(int(t.streamSendQuota)) | 378 | t.activeStreams[streamID] = s |
318 | t.activeStreams[s.id] = s | ||
319 | if len(t.activeStreams) == 1 { | 379 | if len(t.activeStreams) == 1 { |
320 | t.idle = time.Time{} | 380 | t.idle = time.Time{} |
321 | } | 381 | } |
322 | t.mu.Unlock() | 382 | t.mu.Unlock() |
383 | if channelz.IsOn() { | ||
384 | atomic.AddInt64(&t.czData.streamsStarted, 1) | ||
385 | atomic.StoreInt64(&t.czData.lastStreamCreatedTime, time.Now().UnixNano()) | ||
386 | } | ||
323 | s.requestRead = func(n int) { | 387 | s.requestRead = func(n int) { |
324 | t.adjustWindow(s, uint32(n)) | 388 | t.adjustWindow(s, uint32(n)) |
325 | } | 389 | } |
@@ -335,61 +399,51 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( | |||
335 | } | 399 | } |
336 | t.stats.HandleRPC(s.ctx, inHeader) | 400 | t.stats.HandleRPC(s.ctx, inHeader) |
337 | } | 401 | } |
402 | s.ctxDone = s.ctx.Done() | ||
403 | s.wq = newWriteQuota(defaultWriteQuota, s.ctxDone) | ||
404 | s.trReader = &transportReader{ | ||
405 | reader: &recvBufferReader{ | ||
406 | ctx: s.ctx, | ||
407 | ctxDone: s.ctxDone, | ||
408 | recv: s.buf, | ||
409 | }, | ||
410 | windowHandler: func(n int) { | ||
411 | t.updateWindow(s, uint32(n)) | ||
412 | }, | ||
413 | } | ||
414 | // Register the stream with loopy. | ||
415 | t.controlBuf.put(®isterStream{ | ||
416 | streamID: s.id, | ||
417 | wq: s.wq, | ||
418 | }) | ||
338 | handle(s) | 419 | handle(s) |
339 | return | 420 | return false |
340 | } | 421 | } |
341 | 422 | ||
342 | // HandleStreams receives incoming streams using the given handler. This is | 423 | // HandleStreams receives incoming streams using the given handler. This is |
343 | // typically run in a separate goroutine. | 424 | // typically run in a separate goroutine. |
344 | // traceCtx attaches trace to ctx and returns the new context. | 425 | // traceCtx attaches trace to ctx and returns the new context. |
345 | func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.Context, string) context.Context) { | 426 | func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.Context, string) context.Context) { |
346 | // Check the validity of client preface. | 427 | defer close(t.readerDone) |
347 | preface := make([]byte, len(clientPreface)) | ||
348 | if _, err := io.ReadFull(t.conn, preface); err != nil { | ||
349 | // Only log if it isn't a simple tcp accept check (ie: tcp balancer doing open/close socket) | ||
350 | if err != io.EOF { | ||
351 | errorf("transport: http2Server.HandleStreams failed to receive the preface from client: %v", err) | ||
352 | } | ||
353 | t.Close() | ||
354 | return | ||
355 | } | ||
356 | if !bytes.Equal(preface, clientPreface) { | ||
357 | errorf("transport: http2Server.HandleStreams received bogus greeting from client: %q", preface) | ||
358 | t.Close() | ||
359 | return | ||
360 | } | ||
361 | |||
362 | frame, err := t.framer.readFrame() | ||
363 | if err == io.EOF || err == io.ErrUnexpectedEOF { | ||
364 | t.Close() | ||
365 | return | ||
366 | } | ||
367 | if err != nil { | ||
368 | errorf("transport: http2Server.HandleStreams failed to read initial settings frame: %v", err) | ||
369 | t.Close() | ||
370 | return | ||
371 | } | ||
372 | atomic.StoreUint32(&t.activity, 1) | ||
373 | sf, ok := frame.(*http2.SettingsFrame) | ||
374 | if !ok { | ||
375 | errorf("transport: http2Server.HandleStreams saw invalid preface type %T from client", frame) | ||
376 | t.Close() | ||
377 | return | ||
378 | } | ||
379 | t.handleSettings(sf) | ||
380 | |||
381 | for { | 428 | for { |
382 | frame, err := t.framer.readFrame() | 429 | frame, err := t.framer.fr.ReadFrame() |
383 | atomic.StoreUint32(&t.activity, 1) | 430 | atomic.StoreUint32(&t.activity, 1) |
384 | if err != nil { | 431 | if err != nil { |
385 | if se, ok := err.(http2.StreamError); ok { | 432 | if se, ok := err.(http2.StreamError); ok { |
433 | warningf("transport: http2Server.HandleStreams encountered http2.StreamError: %v", se) | ||
386 | t.mu.Lock() | 434 | t.mu.Lock() |
387 | s := t.activeStreams[se.StreamID] | 435 | s := t.activeStreams[se.StreamID] |
388 | t.mu.Unlock() | 436 | t.mu.Unlock() |
389 | if s != nil { | 437 | if s != nil { |
390 | t.closeStream(s) | 438 | t.closeStream(s, true, se.Code, nil, false) |
439 | } else { | ||
440 | t.controlBuf.put(&cleanupStream{ | ||
441 | streamID: se.StreamID, | ||
442 | rst: true, | ||
443 | rstCode: se.Code, | ||
444 | onWrite: func() {}, | ||
445 | }) | ||
391 | } | 446 | } |
392 | t.controlBuf.put(&resetStream{se.StreamID, se.Code}) | ||
393 | continue | 447 | continue |
394 | } | 448 | } |
395 | if err == io.EOF || err == io.ErrUnexpectedEOF { | 449 | if err == io.EOF || err == io.ErrUnexpectedEOF { |
@@ -443,33 +497,20 @@ func (t *http2Server) getStream(f http2.Frame) (*Stream, bool) { | |||
443 | // of stream if the application is requesting data larger in size than | 497 | // of stream if the application is requesting data larger in size than |
444 | // the window. | 498 | // the window. |
445 | func (t *http2Server) adjustWindow(s *Stream, n uint32) { | 499 | func (t *http2Server) adjustWindow(s *Stream, n uint32) { |
446 | s.mu.Lock() | ||
447 | defer s.mu.Unlock() | ||
448 | if s.state == streamDone { | ||
449 | return | ||
450 | } | ||
451 | if w := s.fc.maybeAdjust(n); w > 0 { | 500 | if w := s.fc.maybeAdjust(n); w > 0 { |
452 | if cw := t.fc.resetPendingUpdate(); cw > 0 { | 501 | t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, increment: w}) |
453 | t.controlBuf.put(&windowUpdate{0, cw, false}) | ||
454 | } | ||
455 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | ||
456 | } | 502 | } |
503 | |||
457 | } | 504 | } |
458 | 505 | ||
459 | // updateWindow adjusts the inbound quota for the stream and the transport. | 506 | // updateWindow adjusts the inbound quota for the stream and the transport. |
460 | // Window updates will deliver to the controller for sending when | 507 | // Window updates will deliver to the controller for sending when |
461 | // the cumulative quota exceeds the corresponding threshold. | 508 | // the cumulative quota exceeds the corresponding threshold. |
462 | func (t *http2Server) updateWindow(s *Stream, n uint32) { | 509 | func (t *http2Server) updateWindow(s *Stream, n uint32) { |
463 | s.mu.Lock() | ||
464 | defer s.mu.Unlock() | ||
465 | if s.state == streamDone { | ||
466 | return | ||
467 | } | ||
468 | if w := s.fc.onRead(n); w > 0 { | 510 | if w := s.fc.onRead(n); w > 0 { |
469 | if cw := t.fc.resetPendingUpdate(); cw > 0 { | 511 | t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, |
470 | t.controlBuf.put(&windowUpdate{0, cw, false}) | 512 | increment: w, |
471 | } | 513 | }) |
472 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | ||
473 | } | 514 | } |
474 | } | 515 | } |
475 | 516 | ||
@@ -483,13 +524,15 @@ func (t *http2Server) updateFlowControl(n uint32) { | |||
483 | } | 524 | } |
484 | t.initialWindowSize = int32(n) | 525 | t.initialWindowSize = int32(n) |
485 | t.mu.Unlock() | 526 | t.mu.Unlock() |
486 | t.controlBuf.put(&windowUpdate{0, t.fc.newLimit(n), false}) | 527 | t.controlBuf.put(&outgoingWindowUpdate{ |
487 | t.controlBuf.put(&settings{ | 528 | streamID: 0, |
488 | ack: false, | 529 | increment: t.fc.newLimit(n), |
530 | }) | ||
531 | t.controlBuf.put(&outgoingSettings{ | ||
489 | ss: []http2.Setting{ | 532 | ss: []http2.Setting{ |
490 | { | 533 | { |
491 | ID: http2.SettingInitialWindowSize, | 534 | ID: http2.SettingInitialWindowSize, |
492 | Val: uint32(n), | 535 | Val: n, |
493 | }, | 536 | }, |
494 | }, | 537 | }, |
495 | }) | 538 | }) |
@@ -500,7 +543,7 @@ func (t *http2Server) handleData(f *http2.DataFrame) { | |||
500 | size := f.Header().Length | 543 | size := f.Header().Length |
501 | var sendBDPPing bool | 544 | var sendBDPPing bool |
502 | if t.bdpEst != nil { | 545 | if t.bdpEst != nil { |
503 | sendBDPPing = t.bdpEst.add(uint32(size)) | 546 | sendBDPPing = t.bdpEst.add(size) |
504 | } | 547 | } |
505 | // Decouple connection's flow control from application's read. | 548 | // Decouple connection's flow control from application's read. |
506 | // An update on connection's flow control should not depend on | 549 | // An update on connection's flow control should not depend on |
@@ -510,21 +553,22 @@ func (t *http2Server) handleData(f *http2.DataFrame) { | |||
510 | // Decoupling the connection flow control will prevent other | 553 | // Decoupling the connection flow control will prevent other |
511 | // active(fast) streams from starving in presence of slow or | 554 | // active(fast) streams from starving in presence of slow or |
512 | // inactive streams. | 555 | // inactive streams. |
513 | // | 556 | if w := t.fc.onData(size); w > 0 { |
514 | // Furthermore, if a bdpPing is being sent out we can piggyback | 557 | t.controlBuf.put(&outgoingWindowUpdate{ |
515 | // connection's window update for the bytes we just received. | 558 | streamID: 0, |
559 | increment: w, | ||
560 | }) | ||
561 | } | ||
516 | if sendBDPPing { | 562 | if sendBDPPing { |
517 | t.controlBuf.put(&windowUpdate{0, uint32(size), false}) | 563 | // Avoid excessive ping detection (e.g. in an L7 proxy) |
518 | t.controlBuf.put(bdpPing) | 564 | // by sending a window update prior to the BDP ping. |
519 | } else { | 565 | if w := t.fc.reset(); w > 0 { |
520 | if err := t.fc.onData(uint32(size)); err != nil { | 566 | t.controlBuf.put(&outgoingWindowUpdate{ |
521 | errorf("transport: http2Server %v", err) | 567 | streamID: 0, |
522 | t.Close() | 568 | increment: w, |
523 | return | 569 | }) |
524 | } | ||
525 | if w := t.fc.onRead(uint32(size)); w > 0 { | ||
526 | t.controlBuf.put(&windowUpdate{0, w, true}) | ||
527 | } | 570 | } |
571 | t.controlBuf.put(bdpPing) | ||
528 | } | 572 | } |
529 | // Select the right stream to dispatch. | 573 | // Select the right stream to dispatch. |
530 | s, ok := t.getStream(f) | 574 | s, ok := t.getStream(f) |
@@ -532,23 +576,15 @@ func (t *http2Server) handleData(f *http2.DataFrame) { | |||
532 | return | 576 | return |
533 | } | 577 | } |
534 | if size > 0 { | 578 | if size > 0 { |
535 | s.mu.Lock() | 579 | if err := s.fc.onData(size); err != nil { |
536 | if s.state == streamDone { | 580 | t.closeStream(s, true, http2.ErrCodeFlowControl, nil, false) |
537 | s.mu.Unlock() | ||
538 | return | ||
539 | } | ||
540 | if err := s.fc.onData(uint32(size)); err != nil { | ||
541 | s.mu.Unlock() | ||
542 | t.closeStream(s) | ||
543 | t.controlBuf.put(&resetStream{s.id, http2.ErrCodeFlowControl}) | ||
544 | return | 581 | return |
545 | } | 582 | } |
546 | if f.Header().Flags.Has(http2.FlagDataPadded) { | 583 | if f.Header().Flags.Has(http2.FlagDataPadded) { |
547 | if w := s.fc.onRead(uint32(size) - uint32(len(f.Data()))); w > 0 { | 584 | if w := s.fc.onRead(size - uint32(len(f.Data()))); w > 0 { |
548 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | 585 | t.controlBuf.put(&outgoingWindowUpdate{s.id, w}) |
549 | } | 586 | } |
550 | } | 587 | } |
551 | s.mu.Unlock() | ||
552 | // TODO(bradfitz, zhaoq): A copy is required here because there is no | 588 | // TODO(bradfitz, zhaoq): A copy is required here because there is no |
553 | // guarantee f.Data() is consumed before the arrival of next frame. | 589 | // guarantee f.Data() is consumed before the arrival of next frame. |
554 | // Can this copy be eliminated? | 590 | // Can this copy be eliminated? |
@@ -560,11 +596,7 @@ func (t *http2Server) handleData(f *http2.DataFrame) { | |||
560 | } | 596 | } |
561 | if f.Header().Flags.Has(http2.FlagDataEndStream) { | 597 | if f.Header().Flags.Has(http2.FlagDataEndStream) { |
562 | // Received the end of stream from the client. | 598 | // Received the end of stream from the client. |
563 | s.mu.Lock() | 599 | s.compareAndSwapState(streamActive, streamReadDone) |
564 | if s.state != streamDone { | ||
565 | s.state = streamReadDone | ||
566 | } | ||
567 | s.mu.Unlock() | ||
568 | s.write(recvMsg{err: io.EOF}) | 600 | s.write(recvMsg{err: io.EOF}) |
569 | } | 601 | } |
570 | } | 602 | } |
@@ -574,7 +606,7 @@ func (t *http2Server) handleRSTStream(f *http2.RSTStreamFrame) { | |||
574 | if !ok { | 606 | if !ok { |
575 | return | 607 | return |
576 | } | 608 | } |
577 | t.closeStream(s) | 609 | t.closeStream(s, false, 0, nil, false) |
578 | } | 610 | } |
579 | 611 | ||
580 | func (t *http2Server) handleSettings(f *http2.SettingsFrame) { | 612 | func (t *http2Server) handleSettings(f *http2.SettingsFrame) { |
@@ -582,12 +614,27 @@ func (t *http2Server) handleSettings(f *http2.SettingsFrame) { | |||
582 | return | 614 | return |
583 | } | 615 | } |
584 | var ss []http2.Setting | 616 | var ss []http2.Setting |
617 | var updateFuncs []func() | ||
585 | f.ForeachSetting(func(s http2.Setting) error { | 618 | f.ForeachSetting(func(s http2.Setting) error { |
586 | ss = append(ss, s) | 619 | switch s.ID { |
620 | case http2.SettingMaxHeaderListSize: | ||
621 | updateFuncs = append(updateFuncs, func() { | ||
622 | t.maxSendHeaderListSize = new(uint32) | ||
623 | *t.maxSendHeaderListSize = s.Val | ||
624 | }) | ||
625 | default: | ||
626 | ss = append(ss, s) | ||
627 | } | ||
587 | return nil | 628 | return nil |
588 | }) | 629 | }) |
589 | // The settings will be applied once the ack is sent. | 630 | t.controlBuf.executeAndPut(func(interface{}) bool { |
590 | t.controlBuf.put(&settings{ack: true, ss: ss}) | 631 | for _, f := range updateFuncs { |
632 | f() | ||
633 | } | ||
634 | return true | ||
635 | }, &incomingSettings{ | ||
636 | ss: ss, | ||
637 | }) | ||
591 | } | 638 | } |
592 | 639 | ||
593 | const ( | 640 | const ( |
@@ -627,7 +674,7 @@ func (t *http2Server) handlePing(f *http2.PingFrame) { | |||
627 | t.mu.Unlock() | 674 | t.mu.Unlock() |
628 | if ns < 1 && !t.kep.PermitWithoutStream { | 675 | if ns < 1 && !t.kep.PermitWithoutStream { |
629 | // Keepalive shouldn't be active thus, this new ping should | 676 | // Keepalive shouldn't be active thus, this new ping should |
630 | // have come after atleast defaultPingTimeout. | 677 | // have come after at least defaultPingTimeout. |
631 | if t.lastPingAt.Add(defaultPingTimeout).After(now) { | 678 | if t.lastPingAt.Add(defaultPingTimeout).After(now) { |
632 | t.pingStrikes++ | 679 | t.pingStrikes++ |
633 | } | 680 | } |
@@ -640,69 +687,52 @@ func (t *http2Server) handlePing(f *http2.PingFrame) { | |||
640 | 687 | ||
641 | if t.pingStrikes > maxPingStrikes { | 688 | if t.pingStrikes > maxPingStrikes { |
642 | // Send goaway and close the connection. | 689 | // Send goaway and close the connection. |
690 | errorf("transport: Got too many pings from the client, closing the connection.") | ||
643 | t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: true}) | 691 | t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: true}) |
644 | } | 692 | } |
645 | } | 693 | } |
646 | 694 | ||
647 | func (t *http2Server) handleWindowUpdate(f *http2.WindowUpdateFrame) { | 695 | func (t *http2Server) handleWindowUpdate(f *http2.WindowUpdateFrame) { |
648 | id := f.Header().StreamID | 696 | t.controlBuf.put(&incomingWindowUpdate{ |
649 | incr := f.Increment | 697 | streamID: f.Header().StreamID, |
650 | if id == 0 { | 698 | increment: f.Increment, |
651 | t.sendQuotaPool.add(int(incr)) | 699 | }) |
652 | return | ||
653 | } | ||
654 | if s, ok := t.getStream(f); ok { | ||
655 | s.sendQuotaPool.add(int(incr)) | ||
656 | } | ||
657 | } | 700 | } |
658 | 701 | ||
659 | func (t *http2Server) writeHeaders(s *Stream, b *bytes.Buffer, endStream bool) error { | 702 | func appendHeaderFieldsFromMD(headerFields []hpack.HeaderField, md metadata.MD) []hpack.HeaderField { |
660 | first := true | 703 | for k, vv := range md { |
661 | endHeaders := false | 704 | if isReservedHeader(k) { |
662 | var err error | 705 | // Clients don't tolerate reading restricted headers after some non restricted ones were sent. |
663 | defer func() { | 706 | continue |
664 | if err == nil { | ||
665 | // Reset ping strikes when seding headers since that might cause the | ||
666 | // peer to send ping. | ||
667 | atomic.StoreUint32(&t.resetPingStrikes, 1) | ||
668 | } | ||
669 | }() | ||
670 | // Sends the headers in a single batch. | ||
671 | for !endHeaders { | ||
672 | size := t.hBuf.Len() | ||
673 | if size > http2MaxFrameLen { | ||
674 | size = http2MaxFrameLen | ||
675 | } else { | ||
676 | endHeaders = true | ||
677 | } | 707 | } |
678 | if first { | 708 | for _, v := range vv { |
679 | p := http2.HeadersFrameParam{ | 709 | headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) |
680 | StreamID: s.id, | ||
681 | BlockFragment: b.Next(size), | ||
682 | EndStream: endStream, | ||
683 | EndHeaders: endHeaders, | ||
684 | } | ||
685 | err = t.framer.writeHeaders(endHeaders, p) | ||
686 | first = false | ||
687 | } else { | ||
688 | err = t.framer.writeContinuation(endHeaders, s.id, endHeaders, b.Next(size)) | ||
689 | } | 710 | } |
690 | if err != nil { | 711 | } |
691 | t.Close() | 712 | return headerFields |
692 | return connectionErrorf(true, err, "transport: %v", err) | 713 | } |
714 | |||
715 | func (t *http2Server) checkForHeaderListSize(it interface{}) bool { | ||
716 | if t.maxSendHeaderListSize == nil { | ||
717 | return true | ||
718 | } | ||
719 | hdrFrame := it.(*headerFrame) | ||
720 | var sz int64 | ||
721 | for _, f := range hdrFrame.hf { | ||
722 | if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { | ||
723 | errorf("header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize) | ||
724 | return false | ||
693 | } | 725 | } |
694 | } | 726 | } |
695 | return nil | 727 | return true |
696 | } | 728 | } |
697 | 729 | ||
698 | // WriteHeader sends the header metedata md back to the client. | 730 | // WriteHeader sends the header metedata md back to the client. |
699 | func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { | 731 | func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { |
700 | s.mu.Lock() | 732 | if s.updateHeaderSent() || s.getState() == streamDone { |
701 | if s.headerOk || s.state == streamDone { | ||
702 | s.mu.Unlock() | ||
703 | return ErrIllegalHeaderWrite | 733 | return ErrIllegalHeaderWrite |
704 | } | 734 | } |
705 | s.headerOk = true | 735 | s.hdrMu.Lock() |
706 | if md.Len() > 0 { | 736 | if md.Len() > 0 { |
707 | if s.header.Len() > 0 { | 737 | if s.header.Len() > 0 { |
708 | s.header = metadata.Join(s.header, md) | 738 | s.header = metadata.Join(s.header, md) |
@@ -710,37 +740,45 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { | |||
710 | s.header = md | 740 | s.header = md |
711 | } | 741 | } |
712 | } | 742 | } |
713 | md = s.header | 743 | if err := t.writeHeaderLocked(s); err != nil { |
714 | s.mu.Unlock() | 744 | s.hdrMu.Unlock() |
715 | if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil { | ||
716 | return err | 745 | return err |
717 | } | 746 | } |
718 | t.hBuf.Reset() | 747 | s.hdrMu.Unlock() |
719 | t.hEnc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) | 748 | return nil |
720 | t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"}) | 749 | } |
750 | |||
751 | func (t *http2Server) writeHeaderLocked(s *Stream) error { | ||
752 | // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields | ||
753 | // first and create a slice of that exact size. | ||
754 | headerFields := make([]hpack.HeaderField, 0, 2) // at least :status, content-type will be there if none else. | ||
755 | headerFields = append(headerFields, hpack.HeaderField{Name: ":status", Value: "200"}) | ||
756 | headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(s.contentSubtype)}) | ||
721 | if s.sendCompress != "" { | 757 | if s.sendCompress != "" { |
722 | t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress}) | 758 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress}) |
723 | } | 759 | } |
724 | for k, vv := range md { | 760 | headerFields = appendHeaderFieldsFromMD(headerFields, s.header) |
725 | if isReservedHeader(k) { | 761 | success, err := t.controlBuf.executeAndPut(t.checkForHeaderListSize, &headerFrame{ |
726 | // Clients don't tolerate reading restricted headers after some non restricted ones were sent. | 762 | streamID: s.id, |
727 | continue | 763 | hf: headerFields, |
728 | } | 764 | endStream: false, |
729 | for _, v := range vv { | 765 | onWrite: func() { |
730 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | 766 | atomic.StoreUint32(&t.resetPingStrikes, 1) |
767 | }, | ||
768 | }) | ||
769 | if !success { | ||
770 | if err != nil { | ||
771 | return err | ||
731 | } | 772 | } |
732 | } | 773 | t.closeStream(s, true, http2.ErrCodeInternal, nil, false) |
733 | bufLen := t.hBuf.Len() | 774 | return ErrHeaderListSizeLimitViolation |
734 | if err := t.writeHeaders(s, t.hBuf, false); err != nil { | ||
735 | return err | ||
736 | } | 775 | } |
737 | if t.stats != nil { | 776 | if t.stats != nil { |
738 | outHeader := &stats.OutHeader{ | 777 | // Note: WireLength is not set in outHeader. |
739 | WireLength: bufLen, | 778 | // TODO(mmukhi): Revisit this later, if needed. |
740 | } | 779 | outHeader := &stats.OutHeader{} |
741 | t.stats.HandleRPC(s.Context(), outHeader) | 780 | t.stats.HandleRPC(s.Context(), outHeader) |
742 | } | 781 | } |
743 | t.writableChan <- 0 | ||
744 | return nil | 782 | return nil |
745 | } | 783 | } |
746 | 784 | ||
@@ -749,204 +787,108 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { | |||
749 | // TODO(zhaoq): Now it indicates the end of entire stream. Revisit if early | 787 | // TODO(zhaoq): Now it indicates the end of entire stream. Revisit if early |
750 | // OK is adopted. | 788 | // OK is adopted. |
751 | func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { | 789 | func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { |
752 | var headersSent, hasHeader bool | 790 | if s.getState() == streamDone { |
753 | s.mu.Lock() | ||
754 | if s.state == streamDone { | ||
755 | s.mu.Unlock() | ||
756 | return nil | 791 | return nil |
757 | } | 792 | } |
758 | if s.headerOk { | 793 | s.hdrMu.Lock() |
759 | headersSent = true | 794 | // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields |
760 | } | 795 | // first and create a slice of that exact size. |
761 | if s.header.Len() > 0 { | 796 | headerFields := make([]hpack.HeaderField, 0, 2) // grpc-status and grpc-message will be there if none else. |
762 | hasHeader = true | 797 | if !s.updateHeaderSent() { // No headers have been sent. |
763 | } | 798 | if len(s.header) > 0 { // Send a separate header frame. |
764 | s.mu.Unlock() | 799 | if err := t.writeHeaderLocked(s); err != nil { |
765 | 800 | s.hdrMu.Unlock() | |
766 | if !headersSent && hasHeader { | 801 | return err |
767 | t.WriteHeader(s, nil) | 802 | } |
768 | headersSent = true | 803 | } else { // Send a trailer only response. |
769 | } | 804 | headerFields = append(headerFields, hpack.HeaderField{Name: ":status", Value: "200"}) |
770 | 805 | headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(s.contentSubtype)}) | |
771 | if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil { | 806 | } |
772 | return err | ||
773 | } | ||
774 | t.hBuf.Reset() | ||
775 | if !headersSent { | ||
776 | t.hEnc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) | ||
777 | t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"}) | ||
778 | } | 807 | } |
779 | t.hEnc.WriteField( | 808 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status", Value: strconv.Itoa(int(st.Code()))}) |
780 | hpack.HeaderField{ | 809 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())}) |
781 | Name: "grpc-status", | ||
782 | Value: strconv.Itoa(int(st.Code())), | ||
783 | }) | ||
784 | t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())}) | ||
785 | 810 | ||
786 | if p := st.Proto(); p != nil && len(p.Details) > 0 { | 811 | if p := st.Proto(); p != nil && len(p.Details) > 0 { |
787 | stBytes, err := proto.Marshal(p) | 812 | stBytes, err := proto.Marshal(p) |
788 | if err != nil { | 813 | if err != nil { |
789 | // TODO: return error instead, when callers are able to handle it. | 814 | // TODO: return error instead, when callers are able to handle it. |
790 | panic(err) | 815 | grpclog.Errorf("transport: failed to marshal rpc status: %v, error: %v", p, err) |
816 | } else { | ||
817 | headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)}) | ||
791 | } | 818 | } |
792 | |||
793 | t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)}) | ||
794 | } | 819 | } |
795 | 820 | ||
796 | // Attach the trailer metadata. | 821 | // Attach the trailer metadata. |
797 | for k, vv := range s.trailer { | 822 | headerFields = appendHeaderFieldsFromMD(headerFields, s.trailer) |
798 | // Clients don't tolerate reading restricted headers after some non restricted ones were sent. | 823 | trailingHeader := &headerFrame{ |
799 | if isReservedHeader(k) { | 824 | streamID: s.id, |
800 | continue | 825 | hf: headerFields, |
801 | } | 826 | endStream: true, |
802 | for _, v := range vv { | 827 | onWrite: func() { |
803 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | 828 | atomic.StoreUint32(&t.resetPingStrikes, 1) |
804 | } | 829 | }, |
805 | } | 830 | } |
806 | bufLen := t.hBuf.Len() | 831 | s.hdrMu.Unlock() |
807 | if err := t.writeHeaders(s, t.hBuf, true); err != nil { | 832 | success, err := t.controlBuf.execute(t.checkForHeaderListSize, trailingHeader) |
808 | t.Close() | 833 | if !success { |
809 | return err | 834 | if err != nil { |
835 | return err | ||
836 | } | ||
837 | t.closeStream(s, true, http2.ErrCodeInternal, nil, false) | ||
838 | return ErrHeaderListSizeLimitViolation | ||
810 | } | 839 | } |
840 | t.closeStream(s, false, 0, trailingHeader, true) | ||
811 | if t.stats != nil { | 841 | if t.stats != nil { |
812 | outTrailer := &stats.OutTrailer{ | 842 | t.stats.HandleRPC(s.Context(), &stats.OutTrailer{}) |
813 | WireLength: bufLen, | ||
814 | } | ||
815 | t.stats.HandleRPC(s.Context(), outTrailer) | ||
816 | } | 843 | } |
817 | t.closeStream(s) | ||
818 | t.writableChan <- 0 | ||
819 | return nil | 844 | return nil |
820 | } | 845 | } |
821 | 846 | ||
822 | // Write converts the data into HTTP2 data frame and sends it out. Non-nil error | 847 | // Write converts the data into HTTP2 data frame and sends it out. Non-nil error |
823 | // is returns if it fails (e.g., framing error, transport error). | 848 | // is returns if it fails (e.g., framing error, transport error). |
824 | func (t *http2Server) Write(s *Stream, data []byte, opts *Options) (err error) { | 849 | func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { |
825 | // TODO(zhaoq): Support multi-writers for a single stream. | 850 | if !s.isHeaderSent() { // Headers haven't been written yet. |
826 | var writeHeaderFrame bool | 851 | if err := t.WriteHeader(s, nil); err != nil { |
827 | s.mu.Lock() | 852 | // TODO(mmukhi, dfawley): Make sure this is the right code to return. |
828 | if s.state == streamDone { | 853 | return status.Errorf(codes.Internal, "transport: %v", err) |
829 | s.mu.Unlock() | ||
830 | return streamErrorf(codes.Unknown, "the stream has been done") | ||
831 | } | ||
832 | if !s.headerOk { | ||
833 | writeHeaderFrame = true | ||
834 | } | ||
835 | s.mu.Unlock() | ||
836 | if writeHeaderFrame { | ||
837 | t.WriteHeader(s, nil) | ||
838 | } | ||
839 | r := bytes.NewBuffer(data) | ||
840 | var ( | ||
841 | p []byte | ||
842 | oqv uint32 | ||
843 | ) | ||
844 | for { | ||
845 | if r.Len() == 0 && p == nil { | ||
846 | return nil | ||
847 | } | ||
848 | oqv = atomic.LoadUint32(&t.outQuotaVersion) | ||
849 | size := http2MaxFrameLen | ||
850 | // Wait until the stream has some quota to send the data. | ||
851 | sq, err := wait(s.ctx, nil, nil, t.shutdownChan, s.sendQuotaPool.acquire()) | ||
852 | if err != nil { | ||
853 | return err | ||
854 | } | ||
855 | // Wait until the transport has some quota to send the data. | ||
856 | tq, err := wait(s.ctx, nil, nil, t.shutdownChan, t.sendQuotaPool.acquire()) | ||
857 | if err != nil { | ||
858 | return err | ||
859 | } | ||
860 | if sq < size { | ||
861 | size = sq | ||
862 | } | ||
863 | if tq < size { | ||
864 | size = tq | ||
865 | } | 854 | } |
866 | if p == nil { | 855 | } else { |
867 | p = r.Next(size) | 856 | // Writing headers checks for this condition. |
868 | } | 857 | if s.getState() == streamDone { |
869 | ps := len(p) | 858 | // TODO(mmukhi, dfawley): Should the server write also return io.EOF? |
870 | if ps < sq { | 859 | s.cancel() |
871 | // Overbooked stream quota. Return it back. | 860 | select { |
872 | s.sendQuotaPool.add(sq - ps) | 861 | case <-t.ctx.Done(): |
873 | } | 862 | return ErrConnClosing |
874 | if ps < tq { | 863 | default: |
875 | // Overbooked transport quota. Return it back. | ||
876 | t.sendQuotaPool.add(tq - ps) | ||
877 | } | ||
878 | t.framer.adjustNumWriters(1) | ||
879 | // Got some quota. Try to acquire writing privilege on the | ||
880 | // transport. | ||
881 | if _, err := wait(s.ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil { | ||
882 | if _, ok := err.(StreamError); ok { | ||
883 | // Return the connection quota back. | ||
884 | t.sendQuotaPool.add(ps) | ||
885 | } | ||
886 | if t.framer.adjustNumWriters(-1) == 0 { | ||
887 | // This writer is the last one in this batch and has the | ||
888 | // responsibility to flush the buffered frames. It queues | ||
889 | // a flush request to controlBuf instead of flushing directly | ||
890 | // in order to avoid the race with other writing or flushing. | ||
891 | t.controlBuf.put(&flushIO{}) | ||
892 | } | ||
893 | return err | ||
894 | } | ||
895 | select { | ||
896 | case <-s.ctx.Done(): | ||
897 | t.sendQuotaPool.add(ps) | ||
898 | if t.framer.adjustNumWriters(-1) == 0 { | ||
899 | t.controlBuf.put(&flushIO{}) | ||
900 | } | 864 | } |
901 | t.writableChan <- 0 | ||
902 | return ContextErr(s.ctx.Err()) | 865 | return ContextErr(s.ctx.Err()) |
903 | default: | ||
904 | } | ||
905 | if oqv != atomic.LoadUint32(&t.outQuotaVersion) { | ||
906 | // InitialWindowSize settings frame must have been received after we | ||
907 | // acquired send quota but before we got the writable channel. | ||
908 | // We must forsake this write. | ||
909 | t.sendQuotaPool.add(ps) | ||
910 | s.sendQuotaPool.add(ps) | ||
911 | if t.framer.adjustNumWriters(-1) == 0 { | ||
912 | t.controlBuf.put(&flushIO{}) | ||
913 | } | ||
914 | t.writableChan <- 0 | ||
915 | continue | ||
916 | } | ||
917 | var forceFlush bool | ||
918 | if r.Len() == 0 && t.framer.adjustNumWriters(0) == 1 && !opts.Last { | ||
919 | forceFlush = true | ||
920 | } | ||
921 | // Reset ping strikes when sending data since this might cause | ||
922 | // the peer to send ping. | ||
923 | atomic.StoreUint32(&t.resetPingStrikes, 1) | ||
924 | if err := t.framer.writeData(forceFlush, s.id, false, p); err != nil { | ||
925 | t.Close() | ||
926 | return connectionErrorf(true, err, "transport: %v", err) | ||
927 | } | 866 | } |
928 | p = nil | ||
929 | if t.framer.adjustNumWriters(-1) == 0 { | ||
930 | t.framer.flushWrite() | ||
931 | } | ||
932 | t.writableChan <- 0 | ||
933 | } | 867 | } |
934 | 868 | // Add some data to header frame so that we can equally distribute bytes across frames. | |
935 | } | 869 | emptyLen := http2MaxFrameLen - len(hdr) |
936 | 870 | if emptyLen > len(data) { | |
937 | func (t *http2Server) applySettings(ss []http2.Setting) { | 871 | emptyLen = len(data) |
938 | for _, s := range ss { | 872 | } |
939 | if s.ID == http2.SettingInitialWindowSize { | 873 | hdr = append(hdr, data[:emptyLen]...) |
940 | t.mu.Lock() | 874 | data = data[emptyLen:] |
941 | defer t.mu.Unlock() | 875 | df := &dataFrame{ |
942 | for _, stream := range t.activeStreams { | 876 | streamID: s.id, |
943 | stream.sendQuotaPool.add(int(s.Val) - int(t.streamSendQuota)) | 877 | h: hdr, |
944 | } | 878 | d: data, |
945 | t.streamSendQuota = s.Val | 879 | onEachWrite: func() { |
946 | atomic.AddUint32(&t.outQuotaVersion, 1) | 880 | atomic.StoreUint32(&t.resetPingStrikes, 1) |
881 | }, | ||
882 | } | ||
883 | if err := s.wq.get(int32(len(hdr) + len(data))); err != nil { | ||
884 | select { | ||
885 | case <-t.ctx.Done(): | ||
886 | return ErrConnClosing | ||
887 | default: | ||
947 | } | 888 | } |
948 | 889 | return ContextErr(s.ctx.Err()) | |
949 | } | 890 | } |
891 | return t.controlBuf.put(df) | ||
950 | } | 892 | } |
951 | 893 | ||
952 | // keepalive running in a separate goroutine does the following: | 894 | // keepalive running in a separate goroutine does the following: |
@@ -962,7 +904,7 @@ func (t *http2Server) keepalive() { | |||
962 | maxAge := time.NewTimer(t.kp.MaxConnectionAge) | 904 | maxAge := time.NewTimer(t.kp.MaxConnectionAge) |
963 | keepalive := time.NewTimer(t.kp.Time) | 905 | keepalive := time.NewTimer(t.kp.Time) |
964 | // NOTE: All exit paths of this function should reset their | 906 | // NOTE: All exit paths of this function should reset their |
965 | // respecitve timers. A failure to do so will cause the | 907 | // respective timers. A failure to do so will cause the |
966 | // following clean-up to deadlock and eventually leak. | 908 | // following clean-up to deadlock and eventually leak. |
967 | defer func() { | 909 | defer func() { |
968 | if !maxIdle.Stop() { | 910 | if !maxIdle.Stop() { |
@@ -991,7 +933,7 @@ func (t *http2Server) keepalive() { | |||
991 | // The connection has been idle for a duration of keepalive.MaxConnectionIdle or more. | 933 | // The connection has been idle for a duration of keepalive.MaxConnectionIdle or more. |
992 | // Gracefully close the connection. | 934 | // Gracefully close the connection. |
993 | t.drain(http2.ErrCodeNo, []byte{}) | 935 | t.drain(http2.ErrCodeNo, []byte{}) |
994 | // Reseting the timer so that the clean-up doesn't deadlock. | 936 | // Resetting the timer so that the clean-up doesn't deadlock. |
995 | maxIdle.Reset(infinity) | 937 | maxIdle.Reset(infinity) |
996 | return | 938 | return |
997 | } | 939 | } |
@@ -1003,9 +945,9 @@ func (t *http2Server) keepalive() { | |||
1003 | case <-maxAge.C: | 945 | case <-maxAge.C: |
1004 | // Close the connection after grace period. | 946 | // Close the connection after grace period. |
1005 | t.Close() | 947 | t.Close() |
1006 | // Reseting the timer so that the clean-up doesn't deadlock. | 948 | // Resetting the timer so that the clean-up doesn't deadlock. |
1007 | maxAge.Reset(infinity) | 949 | maxAge.Reset(infinity) |
1008 | case <-t.shutdownChan: | 950 | case <-t.ctx.Done(): |
1009 | } | 951 | } |
1010 | return | 952 | return |
1011 | case <-keepalive.C: | 953 | case <-keepalive.C: |
@@ -1016,98 +958,17 @@ func (t *http2Server) keepalive() { | |||
1016 | } | 958 | } |
1017 | if pingSent { | 959 | if pingSent { |
1018 | t.Close() | 960 | t.Close() |
1019 | // Reseting the timer so that the clean-up doesn't deadlock. | 961 | // Resetting the timer so that the clean-up doesn't deadlock. |
1020 | keepalive.Reset(infinity) | 962 | keepalive.Reset(infinity) |
1021 | return | 963 | return |
1022 | } | 964 | } |
1023 | pingSent = true | 965 | pingSent = true |
966 | if channelz.IsOn() { | ||
967 | atomic.AddInt64(&t.czData.kpCount, 1) | ||
968 | } | ||
1024 | t.controlBuf.put(p) | 969 | t.controlBuf.put(p) |
1025 | keepalive.Reset(t.kp.Timeout) | 970 | keepalive.Reset(t.kp.Timeout) |
1026 | case <-t.shutdownChan: | 971 | case <-t.ctx.Done(): |
1027 | return | ||
1028 | } | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | var goAwayPing = &ping{data: [8]byte{1, 6, 1, 8, 0, 3, 3, 9}} | ||
1033 | |||
1034 | // controller running in a separate goroutine takes charge of sending control | ||
1035 | // frames (e.g., window update, reset stream, setting, etc.) to the server. | ||
1036 | func (t *http2Server) controller() { | ||
1037 | for { | ||
1038 | select { | ||
1039 | case i := <-t.controlBuf.get(): | ||
1040 | t.controlBuf.load() | ||
1041 | select { | ||
1042 | case <-t.writableChan: | ||
1043 | switch i := i.(type) { | ||
1044 | case *windowUpdate: | ||
1045 | t.framer.writeWindowUpdate(i.flush, i.streamID, i.increment) | ||
1046 | case *settings: | ||
1047 | if i.ack { | ||
1048 | t.framer.writeSettingsAck(true) | ||
1049 | t.applySettings(i.ss) | ||
1050 | } else { | ||
1051 | t.framer.writeSettings(true, i.ss...) | ||
1052 | } | ||
1053 | case *resetStream: | ||
1054 | t.framer.writeRSTStream(true, i.streamID, i.code) | ||
1055 | case *goAway: | ||
1056 | t.mu.Lock() | ||
1057 | if t.state == closing { | ||
1058 | t.mu.Unlock() | ||
1059 | // The transport is closing. | ||
1060 | return | ||
1061 | } | ||
1062 | sid := t.maxStreamID | ||
1063 | if !i.headsUp { | ||
1064 | // Stop accepting more streams now. | ||
1065 | t.state = draining | ||
1066 | t.mu.Unlock() | ||
1067 | t.framer.writeGoAway(true, sid, i.code, i.debugData) | ||
1068 | if i.closeConn { | ||
1069 | // Abruptly close the connection following the GoAway. | ||
1070 | t.Close() | ||
1071 | } | ||
1072 | t.writableChan <- 0 | ||
1073 | continue | ||
1074 | } | ||
1075 | t.mu.Unlock() | ||
1076 | // For a graceful close, send out a GoAway with stream ID of MaxUInt32, | ||
1077 | // Follow that with a ping and wait for the ack to come back or a timer | ||
1078 | // to expire. During this time accept new streams since they might have | ||
1079 | // originated before the GoAway reaches the client. | ||
1080 | // After getting the ack or timer expiration send out another GoAway this | ||
1081 | // time with an ID of the max stream server intends to process. | ||
1082 | t.framer.writeGoAway(true, math.MaxUint32, http2.ErrCodeNo, []byte{}) | ||
1083 | t.framer.writePing(true, false, goAwayPing.data) | ||
1084 | go func() { | ||
1085 | timer := time.NewTimer(time.Minute) | ||
1086 | defer timer.Stop() | ||
1087 | select { | ||
1088 | case <-t.drainChan: | ||
1089 | case <-timer.C: | ||
1090 | case <-t.shutdownChan: | ||
1091 | return | ||
1092 | } | ||
1093 | t.controlBuf.put(&goAway{code: i.code, debugData: i.debugData}) | ||
1094 | }() | ||
1095 | case *flushIO: | ||
1096 | t.framer.flushWrite() | ||
1097 | case *ping: | ||
1098 | if !i.ack { | ||
1099 | t.bdpEst.timesnap(i.data) | ||
1100 | } | ||
1101 | t.framer.writePing(true, i.ack, i.data) | ||
1102 | default: | ||
1103 | errorf("transport: http2Server.controller got unexpected item type %v\n", i) | ||
1104 | } | ||
1105 | t.writableChan <- 0 | ||
1106 | continue | ||
1107 | case <-t.shutdownChan: | ||
1108 | return | ||
1109 | } | ||
1110 | case <-t.shutdownChan: | ||
1111 | return | 972 | return |
1112 | } | 973 | } |
1113 | } | 974 | } |
@@ -1116,7 +977,7 @@ func (t *http2Server) controller() { | |||
1116 | // Close starts shutting down the http2Server transport. | 977 | // Close starts shutting down the http2Server transport. |
1117 | // TODO(zhaoq): Now the destruction is not blocked on any pending streams. This | 978 | // TODO(zhaoq): Now the destruction is not blocked on any pending streams. This |
1118 | // could cause some resource issue. Revisit this later. | 979 | // could cause some resource issue. Revisit this later. |
1119 | func (t *http2Server) Close() (err error) { | 980 | func (t *http2Server) Close() error { |
1120 | t.mu.Lock() | 981 | t.mu.Lock() |
1121 | if t.state == closing { | 982 | if t.state == closing { |
1122 | t.mu.Unlock() | 983 | t.mu.Unlock() |
@@ -1126,8 +987,12 @@ func (t *http2Server) Close() (err error) { | |||
1126 | streams := t.activeStreams | 987 | streams := t.activeStreams |
1127 | t.activeStreams = nil | 988 | t.activeStreams = nil |
1128 | t.mu.Unlock() | 989 | t.mu.Unlock() |
1129 | close(t.shutdownChan) | 990 | t.controlBuf.finish() |
1130 | err = t.conn.Close() | 991 | t.cancel() |
992 | err := t.conn.Close() | ||
993 | if channelz.IsOn() { | ||
994 | channelz.RemoveEntry(t.channelzID) | ||
995 | } | ||
1131 | // Cancel all active streams. | 996 | // Cancel all active streams. |
1132 | for _, s := range streams { | 997 | for _, s := range streams { |
1133 | s.cancel() | 998 | s.cancel() |
@@ -1136,32 +1001,48 @@ func (t *http2Server) Close() (err error) { | |||
1136 | connEnd := &stats.ConnEnd{} | 1001 | connEnd := &stats.ConnEnd{} |
1137 | t.stats.HandleConn(t.ctx, connEnd) | 1002 | t.stats.HandleConn(t.ctx, connEnd) |
1138 | } | 1003 | } |
1139 | return | 1004 | return err |
1140 | } | 1005 | } |
1141 | 1006 | ||
1142 | // closeStream clears the footprint of a stream when the stream is not needed | 1007 | // closeStream clears the footprint of a stream when the stream is not needed |
1143 | // any more. | 1008 | // any more. |
1144 | func (t *http2Server) closeStream(s *Stream) { | 1009 | func (t *http2Server) closeStream(s *Stream, rst bool, rstCode http2.ErrCode, hdr *headerFrame, eosReceived bool) { |
1145 | t.mu.Lock() | 1010 | if s.swapState(streamDone) == streamDone { |
1146 | delete(t.activeStreams, s.id) | 1011 | // If the stream was already done, return. |
1147 | if len(t.activeStreams) == 0 { | 1012 | return |
1148 | t.idle = time.Now() | ||
1149 | } | ||
1150 | if t.state == draining && len(t.activeStreams) == 0 { | ||
1151 | defer t.Close() | ||
1152 | } | 1013 | } |
1153 | t.mu.Unlock() | ||
1154 | // In case stream sending and receiving are invoked in separate | 1014 | // In case stream sending and receiving are invoked in separate |
1155 | // goroutines (e.g., bi-directional streaming), cancel needs to be | 1015 | // goroutines (e.g., bi-directional streaming), cancel needs to be |
1156 | // called to interrupt the potential blocking on other goroutines. | 1016 | // called to interrupt the potential blocking on other goroutines. |
1157 | s.cancel() | 1017 | s.cancel() |
1158 | s.mu.Lock() | 1018 | cleanup := &cleanupStream{ |
1159 | if s.state == streamDone { | 1019 | streamID: s.id, |
1160 | s.mu.Unlock() | 1020 | rst: rst, |
1161 | return | 1021 | rstCode: rstCode, |
1022 | onWrite: func() { | ||
1023 | t.mu.Lock() | ||
1024 | if t.activeStreams != nil { | ||
1025 | delete(t.activeStreams, s.id) | ||
1026 | if len(t.activeStreams) == 0 { | ||
1027 | t.idle = time.Now() | ||
1028 | } | ||
1029 | } | ||
1030 | t.mu.Unlock() | ||
1031 | if channelz.IsOn() { | ||
1032 | if eosReceived { | ||
1033 | atomic.AddInt64(&t.czData.streamsSucceeded, 1) | ||
1034 | } else { | ||
1035 | atomic.AddInt64(&t.czData.streamsFailed, 1) | ||
1036 | } | ||
1037 | } | ||
1038 | }, | ||
1039 | } | ||
1040 | if hdr != nil { | ||
1041 | hdr.cleanup = cleanup | ||
1042 | t.controlBuf.put(hdr) | ||
1043 | } else { | ||
1044 | t.controlBuf.put(cleanup) | ||
1162 | } | 1045 | } |
1163 | s.state = streamDone | ||
1164 | s.mu.Unlock() | ||
1165 | } | 1046 | } |
1166 | 1047 | ||
1167 | func (t *http2Server) RemoteAddr() net.Addr { | 1048 | func (t *http2Server) RemoteAddr() net.Addr { |
@@ -1182,7 +1063,111 @@ func (t *http2Server) drain(code http2.ErrCode, debugData []byte) { | |||
1182 | t.controlBuf.put(&goAway{code: code, debugData: debugData, headsUp: true}) | 1063 | t.controlBuf.put(&goAway{code: code, debugData: debugData, headsUp: true}) |
1183 | } | 1064 | } |
1184 | 1065 | ||
1185 | var rgen = rand.New(rand.NewSource(time.Now().UnixNano())) | 1066 | var goAwayPing = &ping{data: [8]byte{1, 6, 1, 8, 0, 3, 3, 9}} |
1067 | |||
1068 | // Handles outgoing GoAway and returns true if loopy needs to put itself | ||
1069 | // in draining mode. | ||
1070 | func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { | ||
1071 | t.mu.Lock() | ||
1072 | if t.state == closing { // TODO(mmukhi): This seems unnecessary. | ||
1073 | t.mu.Unlock() | ||
1074 | // The transport is closing. | ||
1075 | return false, ErrConnClosing | ||
1076 | } | ||
1077 | sid := t.maxStreamID | ||
1078 | if !g.headsUp { | ||
1079 | // Stop accepting more streams now. | ||
1080 | t.state = draining | ||
1081 | if len(t.activeStreams) == 0 { | ||
1082 | g.closeConn = true | ||
1083 | } | ||
1084 | t.mu.Unlock() | ||
1085 | if err := t.framer.fr.WriteGoAway(sid, g.code, g.debugData); err != nil { | ||
1086 | return false, err | ||
1087 | } | ||
1088 | if g.closeConn { | ||
1089 | // Abruptly close the connection following the GoAway (via | ||
1090 | // loopywriter). But flush out what's inside the buffer first. | ||
1091 | t.framer.writer.Flush() | ||
1092 | return false, fmt.Errorf("transport: Connection closing") | ||
1093 | } | ||
1094 | return true, nil | ||
1095 | } | ||
1096 | t.mu.Unlock() | ||
1097 | // For a graceful close, send out a GoAway with stream ID of MaxUInt32, | ||
1098 | // Follow that with a ping and wait for the ack to come back or a timer | ||
1099 | // to expire. During this time accept new streams since they might have | ||
1100 | // originated before the GoAway reaches the client. | ||
1101 | // After getting the ack or timer expiration send out another GoAway this | ||
1102 | // time with an ID of the max stream server intends to process. | ||
1103 | if err := t.framer.fr.WriteGoAway(math.MaxUint32, http2.ErrCodeNo, []byte{}); err != nil { | ||
1104 | return false, err | ||
1105 | } | ||
1106 | if err := t.framer.fr.WritePing(false, goAwayPing.data); err != nil { | ||
1107 | return false, err | ||
1108 | } | ||
1109 | go func() { | ||
1110 | timer := time.NewTimer(time.Minute) | ||
1111 | defer timer.Stop() | ||
1112 | select { | ||
1113 | case <-t.drainChan: | ||
1114 | case <-timer.C: | ||
1115 | case <-t.ctx.Done(): | ||
1116 | return | ||
1117 | } | ||
1118 | t.controlBuf.put(&goAway{code: g.code, debugData: g.debugData}) | ||
1119 | }() | ||
1120 | return false, nil | ||
1121 | } | ||
1122 | |||
1123 | func (t *http2Server) ChannelzMetric() *channelz.SocketInternalMetric { | ||
1124 | s := channelz.SocketInternalMetric{ | ||
1125 | StreamsStarted: atomic.LoadInt64(&t.czData.streamsStarted), | ||
1126 | StreamsSucceeded: atomic.LoadInt64(&t.czData.streamsSucceeded), | ||
1127 | StreamsFailed: atomic.LoadInt64(&t.czData.streamsFailed), | ||
1128 | MessagesSent: atomic.LoadInt64(&t.czData.msgSent), | ||
1129 | MessagesReceived: atomic.LoadInt64(&t.czData.msgRecv), | ||
1130 | KeepAlivesSent: atomic.LoadInt64(&t.czData.kpCount), | ||
1131 | LastRemoteStreamCreatedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastStreamCreatedTime)), | ||
1132 | LastMessageSentTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgSentTime)), | ||
1133 | LastMessageReceivedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgRecvTime)), | ||
1134 | LocalFlowControlWindow: int64(t.fc.getSize()), | ||
1135 | SocketOptions: channelz.GetSocketOption(t.conn), | ||
1136 | LocalAddr: t.localAddr, | ||
1137 | RemoteAddr: t.remoteAddr, | ||
1138 | // RemoteName : | ||
1139 | } | ||
1140 | if au, ok := t.authInfo.(credentials.ChannelzSecurityInfo); ok { | ||
1141 | s.Security = au.GetSecurityValue() | ||
1142 | } | ||
1143 | s.RemoteFlowControlWindow = t.getOutFlowWindow() | ||
1144 | return &s | ||
1145 | } | ||
1146 | |||
1147 | func (t *http2Server) IncrMsgSent() { | ||
1148 | atomic.AddInt64(&t.czData.msgSent, 1) | ||
1149 | atomic.StoreInt64(&t.czData.lastMsgSentTime, time.Now().UnixNano()) | ||
1150 | } | ||
1151 | |||
1152 | func (t *http2Server) IncrMsgRecv() { | ||
1153 | atomic.AddInt64(&t.czData.msgRecv, 1) | ||
1154 | atomic.StoreInt64(&t.czData.lastMsgRecvTime, time.Now().UnixNano()) | ||
1155 | } | ||
1156 | |||
1157 | func (t *http2Server) getOutFlowWindow() int64 { | ||
1158 | resp := make(chan uint32) | ||
1159 | timer := time.NewTimer(time.Second) | ||
1160 | defer timer.Stop() | ||
1161 | t.controlBuf.put(&outFlowControlSizeRequest{resp}) | ||
1162 | select { | ||
1163 | case sz := <-resp: | ||
1164 | return int64(sz) | ||
1165 | case <-t.ctxDone: | ||
1166 | return -1 | ||
1167 | case <-timer.C: | ||
1168 | return -2 | ||
1169 | } | ||
1170 | } | ||
1186 | 1171 | ||
1187 | func getJitter(v time.Duration) time.Duration { | 1172 | func getJitter(v time.Duration) time.Duration { |
1188 | if v == infinity { | 1173 | if v == infinity { |
@@ -1190,6 +1175,6 @@ func getJitter(v time.Duration) time.Duration { | |||
1190 | } | 1175 | } |
1191 | // Generate a jitter between +/- 10% of the value. | 1176 | // Generate a jitter between +/- 10% of the value. |
1192 | r := int64(v / 10) | 1177 | r := int64(v / 10) |
1193 | j := rgen.Int63n(2*r) - r | 1178 | j := grpcrand.Int63n(2*r) - r |
1194 | return time.Duration(j) | 1179 | return time.Duration(j) |
1195 | } | 1180 | } |
diff --git a/vendor/google.golang.org/grpc/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go index 685c6fb..77a2cfa 100644 --- a/vendor/google.golang.org/grpc/transport/http_util.go +++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go | |||
@@ -24,12 +24,13 @@ import ( | |||
24 | "encoding/base64" | 24 | "encoding/base64" |
25 | "fmt" | 25 | "fmt" |
26 | "io" | 26 | "io" |
27 | "math" | ||
27 | "net" | 28 | "net" |
28 | "net/http" | 29 | "net/http" |
29 | "strconv" | 30 | "strconv" |
30 | "strings" | 31 | "strings" |
31 | "sync/atomic" | ||
32 | "time" | 32 | "time" |
33 | "unicode/utf8" | ||
33 | 34 | ||
34 | "github.com/golang/protobuf/proto" | 35 | "github.com/golang/protobuf/proto" |
35 | "golang.org/x/net/http2" | 36 | "golang.org/x/net/http2" |
@@ -44,8 +45,12 @@ const ( | |||
44 | http2MaxFrameLen = 16384 // 16KB frame | 45 | http2MaxFrameLen = 16384 // 16KB frame |
45 | // http://http2.github.io/http2-spec/#SettingValues | 46 | // http://http2.github.io/http2-spec/#SettingValues |
46 | http2InitHeaderTableSize = 4096 | 47 | http2InitHeaderTableSize = 4096 |
47 | // http2IOBufSize specifies the buffer size for sending frames. | 48 | // baseContentType is the base content-type for gRPC. This is a valid |
48 | http2IOBufSize = 32 * 1024 | 49 | // content-type on it's own, but can also include a content-subtype such as |
50 | // "proto" as a suffix after "+" or ";". See | ||
51 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests | ||
52 | // for more details. | ||
53 | baseContentType = "application/grpc" | ||
49 | ) | 54 | ) |
50 | 55 | ||
51 | var ( | 56 | var ( |
@@ -64,7 +69,7 @@ var ( | |||
64 | http2.ErrCodeConnect: codes.Internal, | 69 | http2.ErrCodeConnect: codes.Internal, |
65 | http2.ErrCodeEnhanceYourCalm: codes.ResourceExhausted, | 70 | http2.ErrCodeEnhanceYourCalm: codes.ResourceExhausted, |
66 | http2.ErrCodeInadequateSecurity: codes.PermissionDenied, | 71 | http2.ErrCodeInadequateSecurity: codes.PermissionDenied, |
67 | http2.ErrCodeHTTP11Required: codes.FailedPrecondition, | 72 | http2.ErrCodeHTTP11Required: codes.Internal, |
68 | } | 73 | } |
69 | statusCodeConvTab = map[codes.Code]http2.ErrCode{ | 74 | statusCodeConvTab = map[codes.Code]http2.ErrCode{ |
70 | codes.Internal: http2.ErrCodeInternal, | 75 | codes.Internal: http2.ErrCodeInternal, |
@@ -111,7 +116,12 @@ type decodeState struct { | |||
111 | timeout time.Duration | 116 | timeout time.Duration |
112 | method string | 117 | method string |
113 | // key-value metadata map from the peer. | 118 | // key-value metadata map from the peer. |
114 | mdata map[string][]string | 119 | mdata map[string][]string |
120 | statsTags []byte | ||
121 | statsTrace []byte | ||
122 | contentSubtype string | ||
123 | // whether decoding on server side or not | ||
124 | serverSide bool | ||
115 | } | 125 | } |
116 | 126 | ||
117 | // isReservedHeader checks whether hdr belongs to HTTP2 headers | 127 | // isReservedHeader checks whether hdr belongs to HTTP2 headers |
@@ -123,12 +133,16 @@ func isReservedHeader(hdr string) bool { | |||
123 | } | 133 | } |
124 | switch hdr { | 134 | switch hdr { |
125 | case "content-type", | 135 | case "content-type", |
136 | "user-agent", | ||
126 | "grpc-message-type", | 137 | "grpc-message-type", |
127 | "grpc-encoding", | 138 | "grpc-encoding", |
128 | "grpc-message", | 139 | "grpc-message", |
129 | "grpc-status", | 140 | "grpc-status", |
130 | "grpc-timeout", | 141 | "grpc-timeout", |
131 | "grpc-status-details-bin", | 142 | "grpc-status-details-bin", |
143 | // Intentionally exclude grpc-previous-rpc-attempts and | ||
144 | // grpc-retry-pushback-ms, which are "reserved", but their API | ||
145 | // intentionally works via metadata. | ||
132 | "te": | 146 | "te": |
133 | return true | 147 | return true |
134 | default: | 148 | default: |
@@ -136,28 +150,55 @@ func isReservedHeader(hdr string) bool { | |||
136 | } | 150 | } |
137 | } | 151 | } |
138 | 152 | ||
139 | // isWhitelistedPseudoHeader checks whether hdr belongs to HTTP2 pseudoheaders | 153 | // isWhitelistedHeader checks whether hdr should be propagated into metadata |
140 | // that should be propagated into metadata visible to users. | 154 | // visible to users, even though it is classified as "reserved", above. |
141 | func isWhitelistedPseudoHeader(hdr string) bool { | 155 | func isWhitelistedHeader(hdr string) bool { |
142 | switch hdr { | 156 | switch hdr { |
143 | case ":authority": | 157 | case ":authority", "user-agent": |
144 | return true | 158 | return true |
145 | default: | 159 | default: |
146 | return false | 160 | return false |
147 | } | 161 | } |
148 | } | 162 | } |
149 | 163 | ||
150 | func validContentType(t string) bool { | 164 | // contentSubtype returns the content-subtype for the given content-type. The |
151 | e := "application/grpc" | 165 | // given content-type must be a valid content-type that starts with |
152 | if !strings.HasPrefix(t, e) { | 166 | // "application/grpc". A content-subtype will follow "application/grpc" after a |
153 | return false | 167 | // "+" or ";". See |
168 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for | ||
169 | // more details. | ||
170 | // | ||
171 | // If contentType is not a valid content-type for gRPC, the boolean | ||
172 | // will be false, otherwise true. If content-type == "application/grpc", | ||
173 | // "application/grpc+", or "application/grpc;", the boolean will be true, | ||
174 | // but no content-subtype will be returned. | ||
175 | // | ||
176 | // contentType is assumed to be lowercase already. | ||
177 | func contentSubtype(contentType string) (string, bool) { | ||
178 | if contentType == baseContentType { | ||
179 | return "", true | ||
180 | } | ||
181 | if !strings.HasPrefix(contentType, baseContentType) { | ||
182 | return "", false | ||
183 | } | ||
184 | // guaranteed since != baseContentType and has baseContentType prefix | ||
185 | switch contentType[len(baseContentType)] { | ||
186 | case '+', ';': | ||
187 | // this will return true for "application/grpc+" or "application/grpc;" | ||
188 | // which the previous validContentType function tested to be valid, so we | ||
189 | // just say that no content-subtype is specified in this case | ||
190 | return contentType[len(baseContentType)+1:], true | ||
191 | default: | ||
192 | return "", false | ||
154 | } | 193 | } |
155 | // Support variations on the content-type | 194 | } |
156 | // (e.g. "application/grpc+blah", "application/grpc;blah"). | 195 | |
157 | if len(t) > len(e) && t[len(e)] != '+' && t[len(e)] != ';' { | 196 | // contentSubtype is assumed to be lowercase |
158 | return false | 197 | func contentType(contentSubtype string) string { |
198 | if contentSubtype == "" { | ||
199 | return baseContentType | ||
159 | } | 200 | } |
160 | return true | 201 | return baseContentType + "+" + contentSubtype |
161 | } | 202 | } |
162 | 203 | ||
163 | func (d *decodeState) status() *status.Status { | 204 | func (d *decodeState) status() *status.Status { |
@@ -197,13 +238,22 @@ func decodeMetadataHeader(k, v string) (string, error) { | |||
197 | return v, nil | 238 | return v, nil |
198 | } | 239 | } |
199 | 240 | ||
200 | func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error { | 241 | func (d *decodeState) decodeHeader(frame *http2.MetaHeadersFrame) error { |
242 | // frame.Truncated is set to true when framer detects that the current header | ||
243 | // list size hits MaxHeaderListSize limit. | ||
244 | if frame.Truncated { | ||
245 | return status.Error(codes.Internal, "peer header list size exceeded limit") | ||
246 | } | ||
201 | for _, hf := range frame.Fields { | 247 | for _, hf := range frame.Fields { |
202 | if err := d.processHeaderField(hf); err != nil { | 248 | if err := d.processHeaderField(hf); err != nil { |
203 | return err | 249 | return err |
204 | } | 250 | } |
205 | } | 251 | } |
206 | 252 | ||
253 | if d.serverSide { | ||
254 | return nil | ||
255 | } | ||
256 | |||
207 | // If grpc status exists, no need to check further. | 257 | // If grpc status exists, no need to check further. |
208 | if d.rawStatusCode != nil || d.statusGen != nil { | 258 | if d.rawStatusCode != nil || d.statusGen != nil { |
209 | return nil | 259 | return nil |
@@ -212,7 +262,7 @@ func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error | |||
212 | // If grpc status doesn't exist and http status doesn't exist, | 262 | // If grpc status doesn't exist and http status doesn't exist, |
213 | // then it's a malformed header. | 263 | // then it's a malformed header. |
214 | if d.httpStatus == nil { | 264 | if d.httpStatus == nil { |
215 | return streamErrorf(codes.Internal, "malformed header: doesn't contain status(gRPC or HTTP)") | 265 | return status.Error(codes.Internal, "malformed header: doesn't contain status(gRPC or HTTP)") |
216 | } | 266 | } |
217 | 267 | ||
218 | if *(d.httpStatus) != http.StatusOK { | 268 | if *(d.httpStatus) != http.StatusOK { |
@@ -220,33 +270,46 @@ func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error | |||
220 | if !ok { | 270 | if !ok { |
221 | code = codes.Unknown | 271 | code = codes.Unknown |
222 | } | 272 | } |
223 | return streamErrorf(code, http.StatusText(*(d.httpStatus))) | 273 | return status.Error(code, http.StatusText(*(d.httpStatus))) |
224 | } | 274 | } |
225 | 275 | ||
226 | // gRPC status doesn't exist and http status is OK. | 276 | // gRPC status doesn't exist and http status is OK. |
227 | // Set rawStatusCode to be unknown and return nil error. | 277 | // Set rawStatusCode to be unknown and return nil error. |
228 | // So that, if the stream has ended this Unknown status | 278 | // So that, if the stream has ended this Unknown status |
229 | // will be propogated to the user. | 279 | // will be propagated to the user. |
230 | // Otherwise, it will be ignored. In which case, status from | 280 | // Otherwise, it will be ignored. In which case, status from |
231 | // a later trailer, that has StreamEnded flag set, is propogated. | 281 | // a later trailer, that has StreamEnded flag set, is propagated. |
232 | code := int(codes.Unknown) | 282 | code := int(codes.Unknown) |
233 | d.rawStatusCode = &code | 283 | d.rawStatusCode = &code |
234 | return nil | 284 | return nil |
285 | } | ||
235 | 286 | ||
287 | func (d *decodeState) addMetadata(k, v string) { | ||
288 | if d.mdata == nil { | ||
289 | d.mdata = make(map[string][]string) | ||
290 | } | ||
291 | d.mdata[k] = append(d.mdata[k], v) | ||
236 | } | 292 | } |
237 | 293 | ||
238 | func (d *decodeState) processHeaderField(f hpack.HeaderField) error { | 294 | func (d *decodeState) processHeaderField(f hpack.HeaderField) error { |
239 | switch f.Name { | 295 | switch f.Name { |
240 | case "content-type": | 296 | case "content-type": |
241 | if !validContentType(f.Value) { | 297 | contentSubtype, validContentType := contentSubtype(f.Value) |
242 | return streamErrorf(codes.FailedPrecondition, "transport: received the unexpected content-type %q", f.Value) | 298 | if !validContentType { |
299 | return status.Errorf(codes.Internal, "transport: received the unexpected content-type %q", f.Value) | ||
243 | } | 300 | } |
301 | d.contentSubtype = contentSubtype | ||
302 | // TODO: do we want to propagate the whole content-type in the metadata, | ||
303 | // or come up with a way to just propagate the content-subtype if it was set? | ||
304 | // ie {"content-type": "application/grpc+proto"} or {"content-subtype": "proto"} | ||
305 | // in the metadata? | ||
306 | d.addMetadata(f.Name, f.Value) | ||
244 | case "grpc-encoding": | 307 | case "grpc-encoding": |
245 | d.encoding = f.Value | 308 | d.encoding = f.Value |
246 | case "grpc-status": | 309 | case "grpc-status": |
247 | code, err := strconv.Atoi(f.Value) | 310 | code, err := strconv.Atoi(f.Value) |
248 | if err != nil { | 311 | if err != nil { |
249 | return streamErrorf(codes.Internal, "transport: malformed grpc-status: %v", err) | 312 | return status.Errorf(codes.Internal, "transport: malformed grpc-status: %v", err) |
250 | } | 313 | } |
251 | d.rawStatusCode = &code | 314 | d.rawStatusCode = &code |
252 | case "grpc-message": | 315 | case "grpc-message": |
@@ -254,39 +317,51 @@ func (d *decodeState) processHeaderField(f hpack.HeaderField) error { | |||
254 | case "grpc-status-details-bin": | 317 | case "grpc-status-details-bin": |
255 | v, err := decodeBinHeader(f.Value) | 318 | v, err := decodeBinHeader(f.Value) |
256 | if err != nil { | 319 | if err != nil { |
257 | return streamErrorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) | 320 | return status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) |
258 | } | 321 | } |
259 | s := &spb.Status{} | 322 | s := &spb.Status{} |
260 | if err := proto.Unmarshal(v, s); err != nil { | 323 | if err := proto.Unmarshal(v, s); err != nil { |
261 | return streamErrorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) | 324 | return status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) |
262 | } | 325 | } |
263 | d.statusGen = status.FromProto(s) | 326 | d.statusGen = status.FromProto(s) |
264 | case "grpc-timeout": | 327 | case "grpc-timeout": |
265 | d.timeoutSet = true | 328 | d.timeoutSet = true |
266 | var err error | 329 | var err error |
267 | if d.timeout, err = decodeTimeout(f.Value); err != nil { | 330 | if d.timeout, err = decodeTimeout(f.Value); err != nil { |
268 | return streamErrorf(codes.Internal, "transport: malformed time-out: %v", err) | 331 | return status.Errorf(codes.Internal, "transport: malformed time-out: %v", err) |
269 | } | 332 | } |
270 | case ":path": | 333 | case ":path": |
271 | d.method = f.Value | 334 | d.method = f.Value |
272 | case ":status": | 335 | case ":status": |
273 | code, err := strconv.Atoi(f.Value) | 336 | code, err := strconv.Atoi(f.Value) |
274 | if err != nil { | 337 | if err != nil { |
275 | return streamErrorf(codes.Internal, "transport: malformed http-status: %v", err) | 338 | return status.Errorf(codes.Internal, "transport: malformed http-status: %v", err) |
276 | } | 339 | } |
277 | d.httpStatus = &code | 340 | d.httpStatus = &code |
341 | case "grpc-tags-bin": | ||
342 | v, err := decodeBinHeader(f.Value) | ||
343 | if err != nil { | ||
344 | return status.Errorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", err) | ||
345 | } | ||
346 | d.statsTags = v | ||
347 | d.addMetadata(f.Name, string(v)) | ||
348 | case "grpc-trace-bin": | ||
349 | v, err := decodeBinHeader(f.Value) | ||
350 | if err != nil { | ||
351 | return status.Errorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", err) | ||
352 | } | ||
353 | d.statsTrace = v | ||
354 | d.addMetadata(f.Name, string(v)) | ||
278 | default: | 355 | default: |
279 | if !isReservedHeader(f.Name) || isWhitelistedPseudoHeader(f.Name) { | 356 | if isReservedHeader(f.Name) && !isWhitelistedHeader(f.Name) { |
280 | if d.mdata == nil { | 357 | break |
281 | d.mdata = make(map[string][]string) | 358 | } |
282 | } | 359 | v, err := decodeMetadataHeader(f.Name, f.Value) |
283 | v, err := decodeMetadataHeader(f.Name, f.Value) | 360 | if err != nil { |
284 | if err != nil { | 361 | errorf("Failed to decode metadata header (%q, %q): %v", f.Name, f.Value, err) |
285 | errorf("Failed to decode metadata header (%q, %q): %v", f.Name, f.Value, err) | 362 | return nil |
286 | return nil | ||
287 | } | ||
288 | d.mdata[f.Name] = append(d.mdata[f.Name], v) | ||
289 | } | 363 | } |
364 | d.addMetadata(f.Name, v) | ||
290 | } | 365 | } |
291 | return nil | 366 | return nil |
292 | } | 367 | } |
@@ -361,6 +436,10 @@ func decodeTimeout(s string) (time.Duration, error) { | |||
361 | if size < 2 { | 436 | if size < 2 { |
362 | return 0, fmt.Errorf("transport: timeout string is too short: %q", s) | 437 | return 0, fmt.Errorf("transport: timeout string is too short: %q", s) |
363 | } | 438 | } |
439 | if size > 9 { | ||
440 | // Spec allows for 8 digits plus the unit. | ||
441 | return 0, fmt.Errorf("transport: timeout string is too long: %q", s) | ||
442 | } | ||
364 | unit := timeoutUnit(s[size-1]) | 443 | unit := timeoutUnit(s[size-1]) |
365 | d, ok := timeoutUnitToDuration(unit) | 444 | d, ok := timeoutUnitToDuration(unit) |
366 | if !ok { | 445 | if !ok { |
@@ -370,21 +449,27 @@ func decodeTimeout(s string) (time.Duration, error) { | |||
370 | if err != nil { | 449 | if err != nil { |
371 | return 0, err | 450 | return 0, err |
372 | } | 451 | } |
452 | const maxHours = math.MaxInt64 / int64(time.Hour) | ||
453 | if d == time.Hour && t > maxHours { | ||
454 | // This timeout would overflow math.MaxInt64; clamp it. | ||
455 | return time.Duration(math.MaxInt64), nil | ||
456 | } | ||
373 | return d * time.Duration(t), nil | 457 | return d * time.Duration(t), nil |
374 | } | 458 | } |
375 | 459 | ||
376 | const ( | 460 | const ( |
377 | spaceByte = ' ' | 461 | spaceByte = ' ' |
378 | tildaByte = '~' | 462 | tildeByte = '~' |
379 | percentByte = '%' | 463 | percentByte = '%' |
380 | ) | 464 | ) |
381 | 465 | ||
382 | // encodeGrpcMessage is used to encode status code in header field | 466 | // encodeGrpcMessage is used to encode status code in header field |
383 | // "grpc-message". | 467 | // "grpc-message". It does percent encoding and also replaces invalid utf-8 |
384 | // It checks to see if each individual byte in msg is an | 468 | // characters with Unicode replacement character. |
385 | // allowable byte, and then either percent encoding or passing it through. | 469 | // |
386 | // When percent encoding, the byte is converted into hexadecimal notation | 470 | // It checks to see if each individual byte in msg is an allowable byte, and |
387 | // with a '%' prepended. | 471 | // then either percent encoding or passing it through. When percent encoding, |
472 | // the byte is converted into hexadecimal notation with a '%' prepended. | ||
388 | func encodeGrpcMessage(msg string) string { | 473 | func encodeGrpcMessage(msg string) string { |
389 | if msg == "" { | 474 | if msg == "" { |
390 | return "" | 475 | return "" |
@@ -392,7 +477,7 @@ func encodeGrpcMessage(msg string) string { | |||
392 | lenMsg := len(msg) | 477 | lenMsg := len(msg) |
393 | for i := 0; i < lenMsg; i++ { | 478 | for i := 0; i < lenMsg; i++ { |
394 | c := msg[i] | 479 | c := msg[i] |
395 | if !(c >= spaceByte && c < tildaByte && c != percentByte) { | 480 | if !(c >= spaceByte && c <= tildeByte && c != percentByte) { |
396 | return encodeGrpcMessageUnchecked(msg) | 481 | return encodeGrpcMessageUnchecked(msg) |
397 | } | 482 | } |
398 | } | 483 | } |
@@ -401,14 +486,26 @@ func encodeGrpcMessage(msg string) string { | |||
401 | 486 | ||
402 | func encodeGrpcMessageUnchecked(msg string) string { | 487 | func encodeGrpcMessageUnchecked(msg string) string { |
403 | var buf bytes.Buffer | 488 | var buf bytes.Buffer |
404 | lenMsg := len(msg) | 489 | for len(msg) > 0 { |
405 | for i := 0; i < lenMsg; i++ { | 490 | r, size := utf8.DecodeRuneInString(msg) |
406 | c := msg[i] | 491 | for _, b := range []byte(string(r)) { |
407 | if c >= spaceByte && c < tildaByte && c != percentByte { | 492 | if size > 1 { |
408 | buf.WriteByte(c) | 493 | // If size > 1, r is not ascii. Always do percent encoding. |
409 | } else { | 494 | buf.WriteString(fmt.Sprintf("%%%02X", b)) |
410 | buf.WriteString(fmt.Sprintf("%%%02X", c)) | 495 | continue |
496 | } | ||
497 | |||
498 | // The for loop is necessary even if size == 1. r could be | ||
499 | // utf8.RuneError. | ||
500 | // | ||
501 | // fmt.Sprintf("%%%02X", utf8.RuneError) gives "%FFFD". | ||
502 | if b >= spaceByte && b <= tildeByte && b != percentByte { | ||
503 | buf.WriteByte(b) | ||
504 | } else { | ||
505 | buf.WriteString(fmt.Sprintf("%%%02X", b)) | ||
506 | } | ||
411 | } | 507 | } |
508 | msg = msg[size:] | ||
412 | } | 509 | } |
413 | return buf.String() | 510 | return buf.String() |
414 | } | 511 | } |
@@ -447,151 +544,80 @@ func decodeGrpcMessageUnchecked(msg string) string { | |||
447 | return buf.String() | 544 | return buf.String() |
448 | } | 545 | } |
449 | 546 | ||
450 | type framer struct { | 547 | type bufWriter struct { |
451 | numWriters int32 | 548 | buf []byte |
452 | reader io.Reader | 549 | offset int |
453 | writer *bufio.Writer | 550 | batchSize int |
454 | fr *http2.Framer | 551 | conn net.Conn |
455 | } | 552 | err error |
456 | |||
457 | func newFramer(conn net.Conn) *framer { | ||
458 | f := &framer{ | ||
459 | reader: bufio.NewReaderSize(conn, http2IOBufSize), | ||
460 | writer: bufio.NewWriterSize(conn, http2IOBufSize), | ||
461 | } | ||
462 | f.fr = http2.NewFramer(f.writer, f.reader) | ||
463 | // Opt-in to Frame reuse API on framer to reduce garbage. | ||
464 | // Frames aren't safe to read from after a subsequent call to ReadFrame. | ||
465 | f.fr.SetReuseFrames() | ||
466 | f.fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil) | ||
467 | return f | ||
468 | } | ||
469 | 553 | ||
470 | func (f *framer) adjustNumWriters(i int32) int32 { | 554 | onFlush func() |
471 | return atomic.AddInt32(&f.numWriters, i) | ||
472 | } | 555 | } |
473 | 556 | ||
474 | // The following writeXXX functions can only be called when the caller gets | 557 | func newBufWriter(conn net.Conn, batchSize int) *bufWriter { |
475 | // unblocked from writableChan channel (i.e., owns the privilege to write). | 558 | return &bufWriter{ |
476 | 559 | buf: make([]byte, batchSize*2), | |
477 | func (f *framer) writeContinuation(forceFlush bool, streamID uint32, endHeaders bool, headerBlockFragment []byte) error { | 560 | batchSize: batchSize, |
478 | if err := f.fr.WriteContinuation(streamID, endHeaders, headerBlockFragment); err != nil { | 561 | conn: conn, |
479 | return err | ||
480 | } | 562 | } |
481 | if forceFlush { | ||
482 | return f.writer.Flush() | ||
483 | } | ||
484 | return nil | ||
485 | } | 563 | } |
486 | 564 | ||
487 | func (f *framer) writeData(forceFlush bool, streamID uint32, endStream bool, data []byte) error { | 565 | func (w *bufWriter) Write(b []byte) (n int, err error) { |
488 | if err := f.fr.WriteData(streamID, endStream, data); err != nil { | 566 | if w.err != nil { |
489 | return err | 567 | return 0, w.err |
490 | } | 568 | } |
491 | if forceFlush { | 569 | if w.batchSize == 0 { // Buffer has been disabled. |
492 | return f.writer.Flush() | 570 | return w.conn.Write(b) |
493 | } | 571 | } |
494 | return nil | 572 | for len(b) > 0 { |
495 | } | 573 | nn := copy(w.buf[w.offset:], b) |
496 | 574 | b = b[nn:] | |
497 | func (f *framer) writeGoAway(forceFlush bool, maxStreamID uint32, code http2.ErrCode, debugData []byte) error { | 575 | w.offset += nn |
498 | if err := f.fr.WriteGoAway(maxStreamID, code, debugData); err != nil { | 576 | n += nn |
499 | return err | 577 | if w.offset >= w.batchSize { |
500 | } | 578 | err = w.Flush() |
501 | if forceFlush { | 579 | } |
502 | return f.writer.Flush() | ||
503 | } | ||
504 | return nil | ||
505 | } | ||
506 | |||
507 | func (f *framer) writeHeaders(forceFlush bool, p http2.HeadersFrameParam) error { | ||
508 | if err := f.fr.WriteHeaders(p); err != nil { | ||
509 | return err | ||
510 | } | ||
511 | if forceFlush { | ||
512 | return f.writer.Flush() | ||
513 | } | ||
514 | return nil | ||
515 | } | ||
516 | |||
517 | func (f *framer) writePing(forceFlush, ack bool, data [8]byte) error { | ||
518 | if err := f.fr.WritePing(ack, data); err != nil { | ||
519 | return err | ||
520 | } | ||
521 | if forceFlush { | ||
522 | return f.writer.Flush() | ||
523 | } | ||
524 | return nil | ||
525 | } | ||
526 | |||
527 | func (f *framer) writePriority(forceFlush bool, streamID uint32, p http2.PriorityParam) error { | ||
528 | if err := f.fr.WritePriority(streamID, p); err != nil { | ||
529 | return err | ||
530 | } | ||
531 | if forceFlush { | ||
532 | return f.writer.Flush() | ||
533 | } | 580 | } |
534 | return nil | 581 | return n, err |
535 | } | 582 | } |
536 | 583 | ||
537 | func (f *framer) writePushPromise(forceFlush bool, p http2.PushPromiseParam) error { | 584 | func (w *bufWriter) Flush() error { |
538 | if err := f.fr.WritePushPromise(p); err != nil { | 585 | if w.err != nil { |
539 | return err | 586 | return w.err |
540 | } | ||
541 | if forceFlush { | ||
542 | return f.writer.Flush() | ||
543 | } | 587 | } |
544 | return nil | 588 | if w.offset == 0 { |
545 | } | 589 | return nil |
546 | |||
547 | func (f *framer) writeRSTStream(forceFlush bool, streamID uint32, code http2.ErrCode) error { | ||
548 | if err := f.fr.WriteRSTStream(streamID, code); err != nil { | ||
549 | return err | ||
550 | } | 590 | } |
551 | if forceFlush { | 591 | if w.onFlush != nil { |
552 | return f.writer.Flush() | 592 | w.onFlush() |
553 | } | 593 | } |
554 | return nil | 594 | _, w.err = w.conn.Write(w.buf[:w.offset]) |
595 | w.offset = 0 | ||
596 | return w.err | ||
555 | } | 597 | } |
556 | 598 | ||
557 | func (f *framer) writeSettings(forceFlush bool, settings ...http2.Setting) error { | 599 | type framer struct { |
558 | if err := f.fr.WriteSettings(settings...); err != nil { | 600 | writer *bufWriter |
559 | return err | 601 | fr *http2.Framer |
560 | } | ||
561 | if forceFlush { | ||
562 | return f.writer.Flush() | ||
563 | } | ||
564 | return nil | ||
565 | } | 602 | } |
566 | 603 | ||
567 | func (f *framer) writeSettingsAck(forceFlush bool) error { | 604 | func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, maxHeaderListSize uint32) *framer { |
568 | if err := f.fr.WriteSettingsAck(); err != nil { | 605 | if writeBufferSize < 0 { |
569 | return err | 606 | writeBufferSize = 0 |
570 | } | 607 | } |
571 | if forceFlush { | 608 | var r io.Reader = conn |
572 | return f.writer.Flush() | 609 | if readBufferSize > 0 { |
610 | r = bufio.NewReaderSize(r, readBufferSize) | ||
573 | } | 611 | } |
574 | return nil | 612 | w := newBufWriter(conn, writeBufferSize) |
575 | } | 613 | f := &framer{ |
576 | 614 | writer: w, | |
577 | func (f *framer) writeWindowUpdate(forceFlush bool, streamID, incr uint32) error { | 615 | fr: http2.NewFramer(w, r), |
578 | if err := f.fr.WriteWindowUpdate(streamID, incr); err != nil { | ||
579 | return err | ||
580 | } | ||
581 | if forceFlush { | ||
582 | return f.writer.Flush() | ||
583 | } | 616 | } |
584 | return nil | 617 | // Opt-in to Frame reuse API on framer to reduce garbage. |
585 | } | 618 | // Frames aren't safe to read from after a subsequent call to ReadFrame. |
586 | 619 | f.fr.SetReuseFrames() | |
587 | func (f *framer) flushWrite() error { | 620 | f.fr.MaxHeaderListSize = maxHeaderListSize |
588 | return f.writer.Flush() | 621 | f.fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil) |
589 | } | 622 | return f |
590 | |||
591 | func (f *framer) readFrame() (http2.Frame, error) { | ||
592 | return f.fr.ReadFrame() | ||
593 | } | ||
594 | |||
595 | func (f *framer) errorDetail() error { | ||
596 | return f.fr.ErrorDetail() | ||
597 | } | 623 | } |
diff --git a/vendor/google.golang.org/grpc/transport/log.go b/vendor/google.golang.org/grpc/internal/transport/log.go index ac8e358..879df80 100644 --- a/vendor/google.golang.org/grpc/transport/log.go +++ b/vendor/google.golang.org/grpc/internal/transport/log.go | |||
@@ -42,9 +42,3 @@ func errorf(format string, args ...interface{}) { | |||
42 | grpclog.Errorf(format, args...) | 42 | grpclog.Errorf(format, args...) |
43 | } | 43 | } |
44 | } | 44 | } |
45 | |||
46 | func fatalf(format string, args ...interface{}) { | ||
47 | if grpclog.V(logLevel) { | ||
48 | grpclog.Fatalf(format, args...) | ||
49 | } | ||
50 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index ec0fe67..2580aa7 100644 --- a/vendor/google.golang.org/grpc/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go | |||
@@ -17,17 +17,19 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | // Package transport defines and implements message oriented communication | 19 | // Package transport defines and implements message oriented communication |
20 | // channel to complete various transactions (e.g., an RPC). | 20 | // channel to complete various transactions (e.g., an RPC). It is meant for |
21 | package transport // import "google.golang.org/grpc/transport" | 21 | // grpc-internal usage and is not intended to be imported directly by users. |
22 | package transport | ||
22 | 23 | ||
23 | import ( | 24 | import ( |
25 | "context" | ||
26 | "errors" | ||
24 | "fmt" | 27 | "fmt" |
25 | "io" | 28 | "io" |
26 | "net" | 29 | "net" |
27 | "sync" | 30 | "sync" |
31 | "sync/atomic" | ||
28 | 32 | ||
29 | "golang.org/x/net/context" | ||
30 | "golang.org/x/net/http2" | ||
31 | "google.golang.org/grpc/codes" | 33 | "google.golang.org/grpc/codes" |
32 | "google.golang.org/grpc/credentials" | 34 | "google.golang.org/grpc/credentials" |
33 | "google.golang.org/grpc/keepalive" | 35 | "google.golang.org/grpc/keepalive" |
@@ -56,6 +58,7 @@ type recvBuffer struct { | |||
56 | c chan recvMsg | 58 | c chan recvMsg |
57 | mu sync.Mutex | 59 | mu sync.Mutex |
58 | backlog []recvMsg | 60 | backlog []recvMsg |
61 | err error | ||
59 | } | 62 | } |
60 | 63 | ||
61 | func newRecvBuffer() *recvBuffer { | 64 | func newRecvBuffer() *recvBuffer { |
@@ -67,20 +70,27 @@ func newRecvBuffer() *recvBuffer { | |||
67 | 70 | ||
68 | func (b *recvBuffer) put(r recvMsg) { | 71 | func (b *recvBuffer) put(r recvMsg) { |
69 | b.mu.Lock() | 72 | b.mu.Lock() |
70 | defer b.mu.Unlock() | 73 | if b.err != nil { |
74 | b.mu.Unlock() | ||
75 | // An error had occurred earlier, don't accept more | ||
76 | // data or errors. | ||
77 | return | ||
78 | } | ||
79 | b.err = r.err | ||
71 | if len(b.backlog) == 0 { | 80 | if len(b.backlog) == 0 { |
72 | select { | 81 | select { |
73 | case b.c <- r: | 82 | case b.c <- r: |
83 | b.mu.Unlock() | ||
74 | return | 84 | return |
75 | default: | 85 | default: |
76 | } | 86 | } |
77 | } | 87 | } |
78 | b.backlog = append(b.backlog, r) | 88 | b.backlog = append(b.backlog, r) |
89 | b.mu.Unlock() | ||
79 | } | 90 | } |
80 | 91 | ||
81 | func (b *recvBuffer) load() { | 92 | func (b *recvBuffer) load() { |
82 | b.mu.Lock() | 93 | b.mu.Lock() |
83 | defer b.mu.Unlock() | ||
84 | if len(b.backlog) > 0 { | 94 | if len(b.backlog) > 0 { |
85 | select { | 95 | select { |
86 | case b.c <- b.backlog[0]: | 96 | case b.c <- b.backlog[0]: |
@@ -89,6 +99,7 @@ func (b *recvBuffer) load() { | |||
89 | default: | 99 | default: |
90 | } | 100 | } |
91 | } | 101 | } |
102 | b.mu.Unlock() | ||
92 | } | 103 | } |
93 | 104 | ||
94 | // get returns the channel that receives a recvMsg in the buffer. | 105 | // get returns the channel that receives a recvMsg in the buffer. |
@@ -102,11 +113,12 @@ func (b *recvBuffer) get() <-chan recvMsg { | |||
102 | // recvBufferReader implements io.Reader interface to read the data from | 113 | // recvBufferReader implements io.Reader interface to read the data from |
103 | // recvBuffer. | 114 | // recvBuffer. |
104 | type recvBufferReader struct { | 115 | type recvBufferReader struct { |
105 | ctx context.Context | 116 | closeStream func(error) // Closes the client transport stream with the given error and nil trailer metadata. |
106 | goAway chan struct{} | 117 | ctx context.Context |
107 | recv *recvBuffer | 118 | ctxDone <-chan struct{} // cache of ctx.Done() (for performance). |
108 | last []byte // Stores the remaining data in the previous calls. | 119 | recv *recvBuffer |
109 | err error | 120 | last []byte // Stores the remaining data in the previous calls. |
121 | err error | ||
110 | } | 122 | } |
111 | 123 | ||
112 | // Read reads the next len(p) bytes from last. If last is drained, it tries to | 124 | // Read reads the next len(p) bytes from last. If last is drained, it tries to |
@@ -116,87 +128,54 @@ func (r *recvBufferReader) Read(p []byte) (n int, err error) { | |||
116 | if r.err != nil { | 128 | if r.err != nil { |
117 | return 0, r.err | 129 | return 0, r.err |
118 | } | 130 | } |
119 | n, r.err = r.read(p) | ||
120 | return n, r.err | ||
121 | } | ||
122 | |||
123 | func (r *recvBufferReader) read(p []byte) (n int, err error) { | ||
124 | if r.last != nil && len(r.last) > 0 { | 131 | if r.last != nil && len(r.last) > 0 { |
125 | // Read remaining data left in last call. | 132 | // Read remaining data left in last call. |
126 | copied := copy(p, r.last) | 133 | copied := copy(p, r.last) |
127 | r.last = r.last[copied:] | 134 | r.last = r.last[copied:] |
128 | return copied, nil | 135 | return copied, nil |
129 | } | 136 | } |
137 | if r.closeStream != nil { | ||
138 | n, r.err = r.readClient(p) | ||
139 | } else { | ||
140 | n, r.err = r.read(p) | ||
141 | } | ||
142 | return n, r.err | ||
143 | } | ||
144 | |||
145 | func (r *recvBufferReader) read(p []byte) (n int, err error) { | ||
130 | select { | 146 | select { |
131 | case <-r.ctx.Done(): | 147 | case <-r.ctxDone: |
132 | return 0, ContextErr(r.ctx.Err()) | 148 | return 0, ContextErr(r.ctx.Err()) |
133 | case <-r.goAway: | ||
134 | return 0, ErrStreamDrain | ||
135 | case m := <-r.recv.get(): | 149 | case m := <-r.recv.get(): |
136 | r.recv.load() | 150 | return r.readAdditional(m, p) |
137 | if m.err != nil { | ||
138 | return 0, m.err | ||
139 | } | ||
140 | copied := copy(p, m.data) | ||
141 | r.last = m.data[copied:] | ||
142 | return copied, nil | ||
143 | } | 151 | } |
144 | } | 152 | } |
145 | 153 | ||
146 | // All items in an out of a controlBuffer should be the same type. | 154 | func (r *recvBufferReader) readClient(p []byte) (n int, err error) { |
147 | type item interface { | 155 | // If the context is canceled, then closes the stream with nil metadata. |
148 | item() | 156 | // closeStream writes its error parameter to r.recv as a recvMsg. |
149 | } | 157 | // r.readAdditional acts on that message and returns the necessary error. |
150 | 158 | select { | |
151 | // controlBuffer is an unbounded channel of item. | 159 | case <-r.ctxDone: |
152 | type controlBuffer struct { | 160 | r.closeStream(ContextErr(r.ctx.Err())) |
153 | c chan item | 161 | m := <-r.recv.get() |
154 | mu sync.Mutex | 162 | return r.readAdditional(m, p) |
155 | backlog []item | 163 | case m := <-r.recv.get(): |
156 | } | 164 | return r.readAdditional(m, p) |
157 | |||
158 | func newControlBuffer() *controlBuffer { | ||
159 | b := &controlBuffer{ | ||
160 | c: make(chan item, 1), | ||
161 | } | 165 | } |
162 | return b | ||
163 | } | 166 | } |
164 | 167 | ||
165 | func (b *controlBuffer) put(r item) { | 168 | func (r *recvBufferReader) readAdditional(m recvMsg, p []byte) (n int, err error) { |
166 | b.mu.Lock() | 169 | r.recv.load() |
167 | defer b.mu.Unlock() | 170 | if m.err != nil { |
168 | if len(b.backlog) == 0 { | 171 | return 0, m.err |
169 | select { | ||
170 | case b.c <- r: | ||
171 | return | ||
172 | default: | ||
173 | } | ||
174 | } | 172 | } |
175 | b.backlog = append(b.backlog, r) | 173 | copied := copy(p, m.data) |
174 | r.last = m.data[copied:] | ||
175 | return copied, nil | ||
176 | } | 176 | } |
177 | 177 | ||
178 | func (b *controlBuffer) load() { | 178 | type streamState uint32 |
179 | b.mu.Lock() | ||
180 | defer b.mu.Unlock() | ||
181 | if len(b.backlog) > 0 { | ||
182 | select { | ||
183 | case b.c <- b.backlog[0]: | ||
184 | b.backlog[0] = nil | ||
185 | b.backlog = b.backlog[1:] | ||
186 | default: | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | // get returns the channel that receives an item in the buffer. | ||
192 | // | ||
193 | // Upon receipt of an item, the caller should call load to send another | ||
194 | // item onto the channel if there is any. | ||
195 | func (b *controlBuffer) get() <-chan item { | ||
196 | return b.c | ||
197 | } | ||
198 | |||
199 | type streamState uint8 | ||
200 | 179 | ||
201 | const ( | 180 | const ( |
202 | streamActive streamState = iota | 181 | streamActive streamState = iota |
@@ -207,65 +186,98 @@ const ( | |||
207 | 186 | ||
208 | // Stream represents an RPC in the transport layer. | 187 | // Stream represents an RPC in the transport layer. |
209 | type Stream struct { | 188 | type Stream struct { |
210 | id uint32 | 189 | id uint32 |
211 | // nil for client side Stream. | 190 | st ServerTransport // nil for client side Stream |
212 | st ServerTransport | 191 | ctx context.Context // the associated context of the stream |
213 | // ctx is the associated context of the stream. | 192 | cancel context.CancelFunc // always nil for client side Stream |
214 | ctx context.Context | 193 | done chan struct{} // closed at the end of stream to unblock writers. On the client side. |
215 | // cancel is always nil for client side Stream. | 194 | ctxDone <-chan struct{} // same as done chan but for server side. Cache of ctx.Done() (for performance) |
216 | cancel context.CancelFunc | 195 | method string // the associated RPC method of the stream |
217 | // done is closed when the final status arrives. | ||
218 | done chan struct{} | ||
219 | // goAway is closed when the server sent GoAways signal before this stream was initiated. | ||
220 | goAway chan struct{} | ||
221 | // method records the associated RPC method of the stream. | ||
222 | method string | ||
223 | recvCompress string | 196 | recvCompress string |
224 | sendCompress string | 197 | sendCompress string |
225 | buf *recvBuffer | 198 | buf *recvBuffer |
226 | trReader io.Reader | 199 | trReader io.Reader |
227 | fc *inFlow | 200 | fc *inFlow |
228 | recvQuota uint32 | 201 | wq *writeQuota |
229 | |||
230 | // TODO: Remote this unused variable. | ||
231 | // The accumulated inbound quota pending for window update. | ||
232 | updateQuota uint32 | ||
233 | 202 | ||
234 | // Callback to state application's intentions to read data. This | 203 | // Callback to state application's intentions to read data. This |
235 | // is used to adjust flow control, if need be. | 204 | // is used to adjust flow control, if needed. |
236 | requestRead func(int) | 205 | requestRead func(int) |
237 | 206 | ||
238 | sendQuotaPool *quotaPool | 207 | headerChan chan struct{} // closed to indicate the end of header metadata. |
239 | // Close headerChan to indicate the end of reception of header metadata. | 208 | headerDone uint32 // set when headerChan is closed. Used to avoid closing headerChan multiple times. |
240 | headerChan chan struct{} | 209 | |
241 | // header caches the received header metadata. | 210 | // hdrMu protects header and trailer metadata on the server-side. |
242 | header metadata.MD | 211 | hdrMu sync.Mutex |
243 | // The key-value map of trailer metadata. | 212 | // On client side, header keeps the received header metadata. |
244 | trailer metadata.MD | 213 | // |
245 | 214 | // On server side, header keeps the header set by SetHeader(). The complete | |
246 | mu sync.RWMutex // guard the following | 215 | // header will merged into this after t.WriteHeader() is called. |
247 | // headerOK becomes true from the first header is about to send. | 216 | header metadata.MD |
248 | headerOk bool | 217 | trailer metadata.MD // the key-value map of trailer metadata. |
249 | state streamState | 218 | |
250 | // true iff headerChan is closed. Used to avoid closing headerChan | 219 | noHeaders bool // set if the client never received headers (set only after the stream is done). |
251 | // multiple times. | 220 | |
252 | headerDone bool | 221 | // On the server-side, headerSent is atomically set to 1 when the headers are sent out. |
253 | // the status error received from the server. | 222 | headerSent uint32 |
223 | |||
224 | state streamState | ||
225 | |||
226 | // On client-side it is the status error received from the server. | ||
227 | // On server-side it is unused. | ||
254 | status *status.Status | 228 | status *status.Status |
255 | // rstStream indicates whether a RST_STREAM frame needs to be sent | 229 | |
256 | // to the server to signify that this stream is closing. | 230 | bytesReceived uint32 // indicates whether any bytes have been received on this stream |
257 | rstStream bool | 231 | unprocessed uint32 // set if the server sends a refused stream or GOAWAY including this stream |
258 | // rstError is the error that needs to be sent along with the RST_STREAM frame. | 232 | |
259 | rstError http2.ErrCode | 233 | // contentSubtype is the content-subtype for requests. |
260 | // bytesSent and bytesReceived indicates whether any bytes have been sent or | 234 | // this must be lowercase or the behavior is undefined. |
261 | // received on this stream. | 235 | contentSubtype string |
262 | bytesSent bool | 236 | } |
263 | bytesReceived bool | 237 | |
238 | // isHeaderSent is only valid on the server-side. | ||
239 | func (s *Stream) isHeaderSent() bool { | ||
240 | return atomic.LoadUint32(&s.headerSent) == 1 | ||
241 | } | ||
242 | |||
243 | // updateHeaderSent updates headerSent and returns true | ||
244 | // if it was alreay set. It is valid only on server-side. | ||
245 | func (s *Stream) updateHeaderSent() bool { | ||
246 | return atomic.SwapUint32(&s.headerSent, 1) == 1 | ||
247 | } | ||
248 | |||
249 | func (s *Stream) swapState(st streamState) streamState { | ||
250 | return streamState(atomic.SwapUint32((*uint32)(&s.state), uint32(st))) | ||
251 | } | ||
252 | |||
253 | func (s *Stream) compareAndSwapState(oldState, newState streamState) bool { | ||
254 | return atomic.CompareAndSwapUint32((*uint32)(&s.state), uint32(oldState), uint32(newState)) | ||
255 | } | ||
256 | |||
257 | func (s *Stream) getState() streamState { | ||
258 | return streamState(atomic.LoadUint32((*uint32)(&s.state))) | ||
259 | } | ||
260 | |||
261 | func (s *Stream) waitOnHeader() error { | ||
262 | if s.headerChan == nil { | ||
263 | // On the server headerChan is always nil since a stream originates | ||
264 | // only after having received headers. | ||
265 | return nil | ||
266 | } | ||
267 | select { | ||
268 | case <-s.ctx.Done(): | ||
269 | return ContextErr(s.ctx.Err()) | ||
270 | case <-s.headerChan: | ||
271 | return nil | ||
272 | } | ||
264 | } | 273 | } |
265 | 274 | ||
266 | // RecvCompress returns the compression algorithm applied to the inbound | 275 | // RecvCompress returns the compression algorithm applied to the inbound |
267 | // message. It is empty string if there is no compression applied. | 276 | // message. It is empty string if there is no compression applied. |
268 | func (s *Stream) RecvCompress() string { | 277 | func (s *Stream) RecvCompress() string { |
278 | if err := s.waitOnHeader(); err != nil { | ||
279 | return "" | ||
280 | } | ||
269 | return s.recvCompress | 281 | return s.recvCompress |
270 | } | 282 | } |
271 | 283 | ||
@@ -274,53 +286,68 @@ func (s *Stream) SetSendCompress(str string) { | |||
274 | s.sendCompress = str | 286 | s.sendCompress = str |
275 | } | 287 | } |
276 | 288 | ||
277 | // Done returns a chanel which is closed when it receives the final status | 289 | // Done returns a channel which is closed when it receives the final status |
278 | // from the server. | 290 | // from the server. |
279 | func (s *Stream) Done() <-chan struct{} { | 291 | func (s *Stream) Done() <-chan struct{} { |
280 | return s.done | 292 | return s.done |
281 | } | 293 | } |
282 | 294 | ||
283 | // GoAway returns a channel which is closed when the server sent GoAways signal | 295 | // Header returns the header metadata of the stream. |
284 | // before this stream was initiated. | 296 | // |
285 | func (s *Stream) GoAway() <-chan struct{} { | 297 | // On client side, it acquires the key-value pairs of header metadata once it is |
286 | return s.goAway | 298 | // available. It blocks until i) the metadata is ready or ii) there is no header |
287 | } | 299 | // metadata or iii) the stream is canceled/expired. |
288 | 300 | // | |
289 | // Header acquires the key-value pairs of header metadata once it | 301 | // On server side, it returns the out header after t.WriteHeader is called. |
290 | // is available. It blocks until i) the metadata is ready or ii) there is no | ||
291 | // header metadata or iii) the stream is canceled/expired. | ||
292 | func (s *Stream) Header() (metadata.MD, error) { | 302 | func (s *Stream) Header() (metadata.MD, error) { |
293 | var err error | 303 | if s.headerChan == nil && s.header != nil { |
294 | select { | 304 | // On server side, return the header in stream. It will be the out |
295 | case <-s.ctx.Done(): | 305 | // header after t.WriteHeader is called. |
296 | err = ContextErr(s.ctx.Err()) | ||
297 | case <-s.goAway: | ||
298 | err = ErrStreamDrain | ||
299 | case <-s.headerChan: | ||
300 | return s.header.Copy(), nil | 306 | return s.header.Copy(), nil |
301 | } | 307 | } |
308 | err := s.waitOnHeader() | ||
302 | // Even if the stream is closed, header is returned if available. | 309 | // Even if the stream is closed, header is returned if available. |
303 | select { | 310 | select { |
304 | case <-s.headerChan: | 311 | case <-s.headerChan: |
312 | if s.header == nil { | ||
313 | return nil, nil | ||
314 | } | ||
305 | return s.header.Copy(), nil | 315 | return s.header.Copy(), nil |
306 | default: | 316 | default: |
307 | } | 317 | } |
308 | return nil, err | 318 | return nil, err |
309 | } | 319 | } |
310 | 320 | ||
321 | // TrailersOnly blocks until a header or trailers-only frame is received and | ||
322 | // then returns true if the stream was trailers-only. If the stream ends | ||
323 | // before headers are received, returns true, nil. If a context error happens | ||
324 | // first, returns it as a status error. Client-side only. | ||
325 | func (s *Stream) TrailersOnly() (bool, error) { | ||
326 | err := s.waitOnHeader() | ||
327 | if err != nil { | ||
328 | return false, err | ||
329 | } | ||
330 | // if !headerDone, some other connection error occurred. | ||
331 | return s.noHeaders && atomic.LoadUint32(&s.headerDone) == 1, nil | ||
332 | } | ||
333 | |||
311 | // Trailer returns the cached trailer metedata. Note that if it is not called | 334 | // Trailer returns the cached trailer metedata. Note that if it is not called |
312 | // after the entire stream is done, it could return an empty MD. Client | 335 | // after the entire stream is done, it could return an empty MD. Client |
313 | // side only. | 336 | // side only. |
337 | // It can be safely read only after stream has ended that is either read | ||
338 | // or write have returned io.EOF. | ||
314 | func (s *Stream) Trailer() metadata.MD { | 339 | func (s *Stream) Trailer() metadata.MD { |
315 | s.mu.RLock() | 340 | c := s.trailer.Copy() |
316 | defer s.mu.RUnlock() | 341 | return c |
317 | return s.trailer.Copy() | ||
318 | } | 342 | } |
319 | 343 | ||
320 | // ServerTransport returns the underlying ServerTransport for the stream. | 344 | // ContentSubtype returns the content-subtype for a request. For example, a |
321 | // The client side stream always returns nil. | 345 | // content-subtype of "proto" will result in a content-type of |
322 | func (s *Stream) ServerTransport() ServerTransport { | 346 | // "application/grpc+proto". This will always be lowercase. See |
323 | return s.st | 347 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for |
348 | // more details. | ||
349 | func (s *Stream) ContentSubtype() string { | ||
350 | return s.contentSubtype | ||
324 | } | 351 | } |
325 | 352 | ||
326 | // Context returns the context of the stream. | 353 | // Context returns the context of the stream. |
@@ -334,34 +361,48 @@ func (s *Stream) Method() string { | |||
334 | } | 361 | } |
335 | 362 | ||
336 | // Status returns the status received from the server. | 363 | // Status returns the status received from the server. |
364 | // Status can be read safely only after the stream has ended, | ||
365 | // that is, after Done() is closed. | ||
337 | func (s *Stream) Status() *status.Status { | 366 | func (s *Stream) Status() *status.Status { |
338 | return s.status | 367 | return s.status |
339 | } | 368 | } |
340 | 369 | ||
341 | // SetHeader sets the header metadata. This can be called multiple times. | 370 | // SetHeader sets the header metadata. This can be called multiple times. |
342 | // Server side only. | 371 | // Server side only. |
372 | // This should not be called in parallel to other data writes. | ||
343 | func (s *Stream) SetHeader(md metadata.MD) error { | 373 | func (s *Stream) SetHeader(md metadata.MD) error { |
344 | s.mu.Lock() | ||
345 | defer s.mu.Unlock() | ||
346 | if s.headerOk || s.state == streamDone { | ||
347 | return ErrIllegalHeaderWrite | ||
348 | } | ||
349 | if md.Len() == 0 { | 374 | if md.Len() == 0 { |
350 | return nil | 375 | return nil |
351 | } | 376 | } |
377 | if s.isHeaderSent() || s.getState() == streamDone { | ||
378 | return ErrIllegalHeaderWrite | ||
379 | } | ||
380 | s.hdrMu.Lock() | ||
352 | s.header = metadata.Join(s.header, md) | 381 | s.header = metadata.Join(s.header, md) |
382 | s.hdrMu.Unlock() | ||
353 | return nil | 383 | return nil |
354 | } | 384 | } |
355 | 385 | ||
386 | // SendHeader sends the given header metadata. The given metadata is | ||
387 | // combined with any metadata set by previous calls to SetHeader and | ||
388 | // then written to the transport stream. | ||
389 | func (s *Stream) SendHeader(md metadata.MD) error { | ||
390 | return s.st.WriteHeader(s, md) | ||
391 | } | ||
392 | |||
356 | // SetTrailer sets the trailer metadata which will be sent with the RPC status | 393 | // SetTrailer sets the trailer metadata which will be sent with the RPC status |
357 | // by the server. This can be called multiple times. Server side only. | 394 | // by the server. This can be called multiple times. Server side only. |
395 | // This should not be called parallel to other data writes. | ||
358 | func (s *Stream) SetTrailer(md metadata.MD) error { | 396 | func (s *Stream) SetTrailer(md metadata.MD) error { |
359 | if md.Len() == 0 { | 397 | if md.Len() == 0 { |
360 | return nil | 398 | return nil |
361 | } | 399 | } |
362 | s.mu.Lock() | 400 | if s.getState() == streamDone { |
363 | defer s.mu.Unlock() | 401 | return ErrIllegalHeaderWrite |
402 | } | ||
403 | s.hdrMu.Lock() | ||
364 | s.trailer = metadata.Join(s.trailer, md) | 404 | s.trailer = metadata.Join(s.trailer, md) |
405 | s.hdrMu.Unlock() | ||
365 | return nil | 406 | return nil |
366 | } | 407 | } |
367 | 408 | ||
@@ -401,26 +442,15 @@ func (t *transportReader) Read(p []byte) (n int, err error) { | |||
401 | return | 442 | return |
402 | } | 443 | } |
403 | 444 | ||
404 | // finish sets the stream's state and status, and closes the done channel. | ||
405 | // s.mu must be held by the caller. st must always be non-nil. | ||
406 | func (s *Stream) finish(st *status.Status) { | ||
407 | s.status = st | ||
408 | s.state = streamDone | ||
409 | close(s.done) | ||
410 | } | ||
411 | |||
412 | // BytesSent indicates whether any bytes have been sent on this stream. | ||
413 | func (s *Stream) BytesSent() bool { | ||
414 | s.mu.Lock() | ||
415 | defer s.mu.Unlock() | ||
416 | return s.bytesSent | ||
417 | } | ||
418 | |||
419 | // BytesReceived indicates whether any bytes have been received on this stream. | 445 | // BytesReceived indicates whether any bytes have been received on this stream. |
420 | func (s *Stream) BytesReceived() bool { | 446 | func (s *Stream) BytesReceived() bool { |
421 | s.mu.Lock() | 447 | return atomic.LoadUint32(&s.bytesReceived) == 1 |
422 | defer s.mu.Unlock() | 448 | } |
423 | return s.bytesReceived | 449 | |
450 | // Unprocessed indicates whether the server did not process this stream -- | ||
451 | // i.e. it sent a refused stream or GOAWAY including this stream ID. | ||
452 | func (s *Stream) Unprocessed() bool { | ||
453 | return atomic.LoadUint32(&s.unprocessed) == 1 | ||
424 | } | 454 | } |
425 | 455 | ||
426 | // GoString is implemented by Stream so context.String() won't | 456 | // GoString is implemented by Stream so context.String() won't |
@@ -429,27 +459,11 @@ func (s *Stream) GoString() string { | |||
429 | return fmt.Sprintf("<stream: %p, %v>", s, s.method) | 459 | return fmt.Sprintf("<stream: %p, %v>", s, s.method) |
430 | } | 460 | } |
431 | 461 | ||
432 | // The key to save transport.Stream in the context. | ||
433 | type streamKey struct{} | ||
434 | |||
435 | // newContextWithStream creates a new context from ctx and attaches stream | ||
436 | // to it. | ||
437 | func newContextWithStream(ctx context.Context, stream *Stream) context.Context { | ||
438 | return context.WithValue(ctx, streamKey{}, stream) | ||
439 | } | ||
440 | |||
441 | // StreamFromContext returns the stream saved in ctx. | ||
442 | func StreamFromContext(ctx context.Context) (s *Stream, ok bool) { | ||
443 | s, ok = ctx.Value(streamKey{}).(*Stream) | ||
444 | return | ||
445 | } | ||
446 | |||
447 | // state of transport | 462 | // state of transport |
448 | type transportState int | 463 | type transportState int |
449 | 464 | ||
450 | const ( | 465 | const ( |
451 | reachable transportState = iota | 466 | reachable transportState = iota |
452 | unreachable | ||
453 | closing | 467 | closing |
454 | draining | 468 | draining |
455 | ) | 469 | ) |
@@ -464,6 +478,10 @@ type ServerConfig struct { | |||
464 | KeepalivePolicy keepalive.EnforcementPolicy | 478 | KeepalivePolicy keepalive.EnforcementPolicy |
465 | InitialWindowSize int32 | 479 | InitialWindowSize int32 |
466 | InitialConnWindowSize int32 | 480 | InitialConnWindowSize int32 |
481 | WriteBufferSize int | ||
482 | ReadBufferSize int | ||
483 | ChannelzParentID int64 | ||
484 | MaxHeaderListSize *uint32 | ||
467 | } | 485 | } |
468 | 486 | ||
469 | // NewServerTransport creates a ServerTransport with conn or non-nil error | 487 | // NewServerTransport creates a ServerTransport with conn or non-nil error |
@@ -476,37 +494,47 @@ func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (S | |||
476 | type ConnectOptions struct { | 494 | type ConnectOptions struct { |
477 | // UserAgent is the application user agent. | 495 | // UserAgent is the application user agent. |
478 | UserAgent string | 496 | UserAgent string |
479 | // Authority is the :authority pseudo-header to use. This field has no effect if | ||
480 | // TransportCredentials is set. | ||
481 | Authority string | ||
482 | // Dialer specifies how to dial a network address. | 497 | // Dialer specifies how to dial a network address. |
483 | Dialer func(context.Context, string) (net.Conn, error) | 498 | Dialer func(context.Context, string) (net.Conn, error) |
484 | // FailOnNonTempDialError specifies if gRPC fails on non-temporary dial errors. | 499 | // FailOnNonTempDialError specifies if gRPC fails on non-temporary dial errors. |
485 | FailOnNonTempDialError bool | 500 | FailOnNonTempDialError bool |
486 | // PerRPCCredentials stores the PerRPCCredentials required to issue RPCs. | 501 | // PerRPCCredentials stores the PerRPCCredentials required to issue RPCs. |
487 | PerRPCCredentials []credentials.PerRPCCredentials | 502 | PerRPCCredentials []credentials.PerRPCCredentials |
488 | // TransportCredentials stores the Authenticator required to setup a client connection. | 503 | // TransportCredentials stores the Authenticator required to setup a client |
504 | // connection. Only one of TransportCredentials and CredsBundle is non-nil. | ||
489 | TransportCredentials credentials.TransportCredentials | 505 | TransportCredentials credentials.TransportCredentials |
506 | // CredsBundle is the credentials bundle to be used. Only one of | ||
507 | // TransportCredentials and CredsBundle is non-nil. | ||
508 | CredsBundle credentials.Bundle | ||
490 | // KeepaliveParams stores the keepalive parameters. | 509 | // KeepaliveParams stores the keepalive parameters. |
491 | KeepaliveParams keepalive.ClientParameters | 510 | KeepaliveParams keepalive.ClientParameters |
492 | // StatsHandler stores the handler for stats. | 511 | // StatsHandler stores the handler for stats. |
493 | StatsHandler stats.Handler | 512 | StatsHandler stats.Handler |
494 | // InitialWindowSize sets the intial window size for a stream. | 513 | // InitialWindowSize sets the initial window size for a stream. |
495 | InitialWindowSize int32 | 514 | InitialWindowSize int32 |
496 | // InitialConnWindowSize sets the intial window size for a connection. | 515 | // InitialConnWindowSize sets the initial window size for a connection. |
497 | InitialConnWindowSize int32 | 516 | InitialConnWindowSize int32 |
517 | // WriteBufferSize sets the size of write buffer which in turn determines how much data can be batched before it's written on the wire. | ||
518 | WriteBufferSize int | ||
519 | // ReadBufferSize sets the size of read buffer, which in turn determines how much data can be read at most for one read syscall. | ||
520 | ReadBufferSize int | ||
521 | // ChannelzParentID sets the addrConn id which initiate the creation of this client transport. | ||
522 | ChannelzParentID int64 | ||
523 | // MaxHeaderListSize sets the max (uncompressed) size of header list that is prepared to be received. | ||
524 | MaxHeaderListSize *uint32 | ||
498 | } | 525 | } |
499 | 526 | ||
500 | // TargetInfo contains the information of the target such as network address and metadata. | 527 | // TargetInfo contains the information of the target such as network address and metadata. |
501 | type TargetInfo struct { | 528 | type TargetInfo struct { |
502 | Addr string | 529 | Addr string |
503 | Metadata interface{} | 530 | Metadata interface{} |
531 | Authority string | ||
504 | } | 532 | } |
505 | 533 | ||
506 | // NewClientTransport establishes the transport with the required ConnectOptions | 534 | // NewClientTransport establishes the transport with the required ConnectOptions |
507 | // and returns it to the caller. | 535 | // and returns it to the caller. |
508 | func NewClientTransport(ctx context.Context, target TargetInfo, opts ConnectOptions) (ClientTransport, error) { | 536 | func NewClientTransport(connectCtx, ctx context.Context, target TargetInfo, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) { |
509 | return newHTTP2Client(ctx, target, opts) | 537 | return newHTTP2Client(connectCtx, ctx, target, opts, onPrefaceReceipt, onGoAway, onClose) |
510 | } | 538 | } |
511 | 539 | ||
512 | // Options provides additional hints and information for message | 540 | // Options provides additional hints and information for message |
@@ -515,11 +543,6 @@ type Options struct { | |||
515 | // Last indicates whether this write is the last piece for | 543 | // Last indicates whether this write is the last piece for |
516 | // this stream. | 544 | // this stream. |
517 | Last bool | 545 | Last bool |
518 | |||
519 | // Delay is a hint to the transport implementation for whether | ||
520 | // the data could be buffered for a batching write. The | ||
521 | // Transport implementation may ignore the hint. | ||
522 | Delay bool | ||
523 | } | 546 | } |
524 | 547 | ||
525 | // CallHdr carries the information of a particular RPC. | 548 | // CallHdr carries the information of a particular RPC. |
@@ -530,10 +553,6 @@ type CallHdr struct { | |||
530 | // Method specifies the operation to perform. | 553 | // Method specifies the operation to perform. |
531 | Method string | 554 | Method string |
532 | 555 | ||
533 | // RecvCompress specifies the compression algorithm applied on | ||
534 | // inbound messages. | ||
535 | RecvCompress string | ||
536 | |||
537 | // SendCompress specifies the compression algorithm applied on | 556 | // SendCompress specifies the compression algorithm applied on |
538 | // outbound message. | 557 | // outbound message. |
539 | SendCompress string | 558 | SendCompress string |
@@ -541,13 +560,15 @@ type CallHdr struct { | |||
541 | // Creds specifies credentials.PerRPCCredentials for a call. | 560 | // Creds specifies credentials.PerRPCCredentials for a call. |
542 | Creds credentials.PerRPCCredentials | 561 | Creds credentials.PerRPCCredentials |
543 | 562 | ||
544 | // Flush indicates whether a new stream command should be sent | 563 | // ContentSubtype specifies the content-subtype for a request. For example, a |
545 | // to the peer without waiting for the first data. This is | 564 | // content-subtype of "proto" will result in a content-type of |
546 | // only a hint. | 565 | // "application/grpc+proto". The value of ContentSubtype must be all |
547 | // If it's true, the transport may modify the flush decision | 566 | // lowercase, otherwise the behavior is undefined. See |
548 | // for performance purposes. | 567 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests |
549 | // If it's false, new stream will never be flushed. | 568 | // for more details. |
550 | Flush bool | 569 | ContentSubtype string |
570 | |||
571 | PreviousAttempts int // value of grpc-previous-rpc-attempts header to set | ||
551 | } | 572 | } |
552 | 573 | ||
553 | // ClientTransport is the common interface for all gRPC client-side transport | 574 | // ClientTransport is the common interface for all gRPC client-side transport |
@@ -564,7 +585,7 @@ type ClientTransport interface { | |||
564 | 585 | ||
565 | // Write sends the data for the given stream. A nil stream indicates | 586 | // Write sends the data for the given stream. A nil stream indicates |
566 | // the write is to be performed on the transport as a whole. | 587 | // the write is to be performed on the transport as a whole. |
567 | Write(s *Stream, data []byte, opts *Options) error | 588 | Write(s *Stream, hdr []byte, data []byte, opts *Options) error |
568 | 589 | ||
569 | // NewStream creates a Stream for an RPC. | 590 | // NewStream creates a Stream for an RPC. |
570 | NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error) | 591 | NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error) |
@@ -589,6 +610,12 @@ type ClientTransport interface { | |||
589 | 610 | ||
590 | // GetGoAwayReason returns the reason why GoAway frame was received. | 611 | // GetGoAwayReason returns the reason why GoAway frame was received. |
591 | GetGoAwayReason() GoAwayReason | 612 | GetGoAwayReason() GoAwayReason |
613 | |||
614 | // IncrMsgSent increments the number of message sent through this transport. | ||
615 | IncrMsgSent() | ||
616 | |||
617 | // IncrMsgRecv increments the number of message received through this transport. | ||
618 | IncrMsgRecv() | ||
592 | } | 619 | } |
593 | 620 | ||
594 | // ServerTransport is the common interface for all gRPC server-side transport | 621 | // ServerTransport is the common interface for all gRPC server-side transport |
@@ -606,7 +633,7 @@ type ServerTransport interface { | |||
606 | 633 | ||
607 | // Write sends the data for the given stream. | 634 | // Write sends the data for the given stream. |
608 | // Write may not be called on all streams. | 635 | // Write may not be called on all streams. |
609 | Write(s *Stream, data []byte, opts *Options) error | 636 | Write(s *Stream, hdr []byte, data []byte, opts *Options) error |
610 | 637 | ||
611 | // WriteStatus sends the status of a stream to the client. WriteStatus is | 638 | // WriteStatus sends the status of a stream to the client. WriteStatus is |
612 | // the final call made on a stream and always occurs. | 639 | // the final call made on a stream and always occurs. |
@@ -622,14 +649,12 @@ type ServerTransport interface { | |||
622 | 649 | ||
623 | // Drain notifies the client this ServerTransport stops accepting new RPCs. | 650 | // Drain notifies the client this ServerTransport stops accepting new RPCs. |
624 | Drain() | 651 | Drain() |
625 | } | ||
626 | 652 | ||
627 | // streamErrorf creates an StreamError with the specified error code and description. | 653 | // IncrMsgSent increments the number of message sent through this transport. |
628 | func streamErrorf(c codes.Code, format string, a ...interface{}) StreamError { | 654 | IncrMsgSent() |
629 | return StreamError{ | 655 | |
630 | Code: c, | 656 | // IncrMsgRecv increments the number of message received through this transport. |
631 | Desc: fmt.Sprintf(format, a...), | 657 | IncrMsgRecv() |
632 | } | ||
633 | } | 658 | } |
634 | 659 | ||
635 | // connectionErrorf creates an ConnectionError with the specified error description. | 660 | // connectionErrorf creates an ConnectionError with the specified error description. |
@@ -671,60 +696,63 @@ func (e ConnectionError) Origin() error { | |||
671 | var ( | 696 | var ( |
672 | // ErrConnClosing indicates that the transport is closing. | 697 | // ErrConnClosing indicates that the transport is closing. |
673 | ErrConnClosing = connectionErrorf(true, nil, "transport is closing") | 698 | ErrConnClosing = connectionErrorf(true, nil, "transport is closing") |
674 | // ErrStreamDrain indicates that the stream is rejected by the server because | 699 | // errStreamDrain indicates that the stream is rejected because the |
675 | // the server stops accepting new RPCs. | 700 | // connection is draining. This could be caused by goaway or balancer |
676 | ErrStreamDrain = streamErrorf(codes.Unavailable, "the server stops accepting new RPCs") | 701 | // removing the address. |
702 | errStreamDrain = status.Error(codes.Unavailable, "the connection is draining") | ||
703 | // errStreamDone is returned from write at the client side to indiacte application | ||
704 | // layer of an error. | ||
705 | errStreamDone = errors.New("the stream is done") | ||
706 | // StatusGoAway indicates that the server sent a GOAWAY that included this | ||
707 | // stream's ID in unprocessed RPCs. | ||
708 | statusGoAway = status.New(codes.Unavailable, "the stream is rejected because server is draining the connection") | ||
677 | ) | 709 | ) |
678 | 710 | ||
679 | // TODO: See if we can replace StreamError with status package errors. | ||
680 | |||
681 | // StreamError is an error that only affects one stream within a connection. | ||
682 | type StreamError struct { | ||
683 | Code codes.Code | ||
684 | Desc string | ||
685 | } | ||
686 | |||
687 | func (e StreamError) Error() string { | ||
688 | return fmt.Sprintf("stream error: code = %s desc = %q", e.Code, e.Desc) | ||
689 | } | ||
690 | |||
691 | // wait blocks until it can receive from ctx.Done, closing, or proceed. | ||
692 | // If it receives from ctx.Done, it returns 0, the StreamError for ctx.Err. | ||
693 | // If it receives from done, it returns 0, io.EOF if ctx is not done; otherwise | ||
694 | // it return the StreamError for ctx.Err. | ||
695 | // If it receives from goAway, it returns 0, ErrStreamDrain. | ||
696 | // If it receives from closing, it returns 0, ErrConnClosing. | ||
697 | // If it receives from proceed, it returns the received integer, nil. | ||
698 | func wait(ctx context.Context, done, goAway, closing <-chan struct{}, proceed <-chan int) (int, error) { | ||
699 | select { | ||
700 | case <-ctx.Done(): | ||
701 | return 0, ContextErr(ctx.Err()) | ||
702 | case <-done: | ||
703 | // User cancellation has precedence. | ||
704 | select { | ||
705 | case <-ctx.Done(): | ||
706 | return 0, ContextErr(ctx.Err()) | ||
707 | default: | ||
708 | } | ||
709 | return 0, io.EOF | ||
710 | case <-goAway: | ||
711 | return 0, ErrStreamDrain | ||
712 | case <-closing: | ||
713 | return 0, ErrConnClosing | ||
714 | case i := <-proceed: | ||
715 | return i, nil | ||
716 | } | ||
717 | } | ||
718 | |||
719 | // GoAwayReason contains the reason for the GoAway frame received. | 711 | // GoAwayReason contains the reason for the GoAway frame received. |
720 | type GoAwayReason uint8 | 712 | type GoAwayReason uint8 |
721 | 713 | ||
722 | const ( | 714 | const ( |
723 | // Invalid indicates that no GoAway frame is received. | 715 | // GoAwayInvalid indicates that no GoAway frame is received. |
724 | Invalid GoAwayReason = 0 | 716 | GoAwayInvalid GoAwayReason = 0 |
725 | // NoReason is the default value when GoAway frame is received. | 717 | // GoAwayNoReason is the default value when GoAway frame is received. |
726 | NoReason GoAwayReason = 1 | 718 | GoAwayNoReason GoAwayReason = 1 |
727 | // TooManyPings indicates that a GoAway frame with ErrCodeEnhanceYourCalm | 719 | // GoAwayTooManyPings indicates that a GoAway frame with |
728 | // was recieved and that the debug data said "too_many_pings". | 720 | // ErrCodeEnhanceYourCalm was received and that the debug data said |
729 | TooManyPings GoAwayReason = 2 | 721 | // "too_many_pings". |
722 | GoAwayTooManyPings GoAwayReason = 2 | ||
730 | ) | 723 | ) |
724 | |||
725 | // channelzData is used to store channelz related data for http2Client and http2Server. | ||
726 | // These fields cannot be embedded in the original structs (e.g. http2Client), since to do atomic | ||
727 | // operation on int64 variable on 32-bit machine, user is responsible to enforce memory alignment. | ||
728 | // Here, by grouping those int64 fields inside a struct, we are enforcing the alignment. | ||
729 | type channelzData struct { | ||
730 | kpCount int64 | ||
731 | // The number of streams that have started, including already finished ones. | ||
732 | streamsStarted int64 | ||
733 | // Client side: The number of streams that have ended successfully by receiving | ||
734 | // EoS bit set frame from server. | ||
735 | // Server side: The number of streams that have ended successfully by sending | ||
736 | // frame with EoS bit set. | ||
737 | streamsSucceeded int64 | ||
738 | streamsFailed int64 | ||
739 | // lastStreamCreatedTime stores the timestamp that the last stream gets created. It is of int64 type | ||
740 | // instead of time.Time since it's more costly to atomically update time.Time variable than int64 | ||
741 | // variable. The same goes for lastMsgSentTime and lastMsgRecvTime. | ||
742 | lastStreamCreatedTime int64 | ||
743 | msgSent int64 | ||
744 | msgRecv int64 | ||
745 | lastMsgSentTime int64 | ||
746 | lastMsgRecvTime int64 | ||
747 | } | ||
748 | |||
749 | // ContextErr converts the error from context package into a status error. | ||
750 | func ContextErr(err error) error { | ||
751 | switch err { | ||
752 | case context.DeadlineExceeded: | ||
753 | return status.Error(codes.DeadlineExceeded, err.Error()) | ||
754 | case context.Canceled: | ||
755 | return status.Error(codes.Canceled, err.Error()) | ||
756 | } | ||
757 | return status.Errorf(codes.Internal, "Unexpected error from context packet: %v", err) | ||
758 | } | ||
diff --git a/vendor/google.golang.org/grpc/keepalive/keepalive.go b/vendor/google.golang.org/grpc/keepalive/keepalive.go index f8adc7e..899e72d 100644 --- a/vendor/google.golang.org/grpc/keepalive/keepalive.go +++ b/vendor/google.golang.org/grpc/keepalive/keepalive.go | |||
@@ -16,7 +16,8 @@ | |||
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | // Package keepalive defines configurable parameters for point-to-point healthcheck. | 19 | // Package keepalive defines configurable parameters for point-to-point |
20 | // healthcheck. | ||
20 | package keepalive | 21 | package keepalive |
21 | 22 | ||
22 | import ( | 23 | import ( |
@@ -24,42 +25,59 @@ import ( | |||
24 | ) | 25 | ) |
25 | 26 | ||
26 | // ClientParameters is used to set keepalive parameters on the client-side. | 27 | // ClientParameters is used to set keepalive parameters on the client-side. |
27 | // These configure how the client will actively probe to notice when a connection is broken | 28 | // These configure how the client will actively probe to notice when a |
28 | // and send pings so intermediaries will be aware of the liveness of the connection. | 29 | // connection is broken and send pings so intermediaries will be aware of the |
29 | // Make sure these parameters are set in coordination with the keepalive policy on the server, | 30 | // liveness of the connection. Make sure these parameters are set in |
30 | // as incompatible settings can result in closing of connection. | 31 | // coordination with the keepalive policy on the server, as incompatible |
32 | // settings can result in closing of connection. | ||
31 | type ClientParameters struct { | 33 | type ClientParameters struct { |
32 | // After a duration of this time if the client doesn't see any activity it pings the server to see if the transport is still alive. | 34 | // After a duration of this time if the client doesn't see any activity it |
35 | // pings the server to see if the transport is still alive. | ||
33 | Time time.Duration // The current default value is infinity. | 36 | Time time.Duration // The current default value is infinity. |
34 | // After having pinged for keepalive check, the client waits for a duration of Timeout and if no activity is seen even after that | 37 | // After having pinged for keepalive check, the client waits for a duration |
35 | // the connection is closed. | 38 | // of Timeout and if no activity is seen even after that the connection is |
39 | // closed. | ||
36 | Timeout time.Duration // The current default value is 20 seconds. | 40 | Timeout time.Duration // The current default value is 20 seconds. |
37 | // If true, client runs keepalive checks even with no active RPCs. | 41 | // If true, client sends keepalive pings even with no active RPCs. If false, |
42 | // when there are no active RPCs, Time and Timeout will be ignored and no | ||
43 | // keepalive pings will be sent. | ||
38 | PermitWithoutStream bool // false by default. | 44 | PermitWithoutStream bool // false by default. |
39 | } | 45 | } |
40 | 46 | ||
41 | // ServerParameters is used to set keepalive and max-age parameters on the server-side. | 47 | // ServerParameters is used to set keepalive and max-age parameters on the |
48 | // server-side. | ||
42 | type ServerParameters struct { | 49 | type ServerParameters struct { |
43 | // MaxConnectionIdle is a duration for the amount of time after which an idle connection would be closed by sending a GoAway. | 50 | // MaxConnectionIdle is a duration for the amount of time after which an |
44 | // Idleness duration is defined since the most recent time the number of outstanding RPCs became zero or the connection establishment. | 51 | // idle connection would be closed by sending a GoAway. Idleness duration is |
52 | // defined since the most recent time the number of outstanding RPCs became | ||
53 | // zero or the connection establishment. | ||
45 | MaxConnectionIdle time.Duration // The current default value is infinity. | 54 | MaxConnectionIdle time.Duration // The current default value is infinity. |
46 | // MaxConnectionAge is a duration for the maximum amount of time a connection may exist before it will be closed by sending a GoAway. | 55 | // MaxConnectionAge is a duration for the maximum amount of time a |
47 | // A random jitter of +/-10% will be added to MaxConnectionAge to spread out connection storms. | 56 | // connection may exist before it will be closed by sending a GoAway. A |
57 | // random jitter of +/-10% will be added to MaxConnectionAge to spread out | ||
58 | // connection storms. | ||
48 | MaxConnectionAge time.Duration // The current default value is infinity. | 59 | MaxConnectionAge time.Duration // The current default value is infinity. |
49 | // MaxConnectinoAgeGrace is an additive period after MaxConnectionAge after which the connection will be forcibly closed. | 60 | // MaxConnectionAgeGrace is an additive period after MaxConnectionAge after |
61 | // which the connection will be forcibly closed. | ||
50 | MaxConnectionAgeGrace time.Duration // The current default value is infinity. | 62 | MaxConnectionAgeGrace time.Duration // The current default value is infinity. |
51 | // After a duration of this time if the server doesn't see any activity it pings the client to see if the transport is still alive. | 63 | // After a duration of this time if the server doesn't see any activity it |
64 | // pings the client to see if the transport is still alive. | ||
52 | Time time.Duration // The current default value is 2 hours. | 65 | Time time.Duration // The current default value is 2 hours. |
53 | // After having pinged for keepalive check, the server waits for a duration of Timeout and if no activity is seen even after that | 66 | // After having pinged for keepalive check, the server waits for a duration |
54 | // the connection is closed. | 67 | // of Timeout and if no activity is seen even after that the connection is |
68 | // closed. | ||
55 | Timeout time.Duration // The current default value is 20 seconds. | 69 | Timeout time.Duration // The current default value is 20 seconds. |
56 | } | 70 | } |
57 | 71 | ||
58 | // EnforcementPolicy is used to set keepalive enforcement policy on the server-side. | 72 | // EnforcementPolicy is used to set keepalive enforcement policy on the |
59 | // Server will close connection with a client that violates this policy. | 73 | // server-side. Server will close connection with a client that violates this |
74 | // policy. | ||
60 | type EnforcementPolicy struct { | 75 | type EnforcementPolicy struct { |
61 | // MinTime is the minimum amount of time a client should wait before sending a keepalive ping. | 76 | // MinTime is the minimum amount of time a client should wait before sending |
77 | // a keepalive ping. | ||
62 | MinTime time.Duration // The current default value is 5 minutes. | 78 | MinTime time.Duration // The current default value is 5 minutes. |
63 | // If true, server expects keepalive pings even when there are no active streams(RPCs). | 79 | // If true, server allows keepalive pings even when there are no active |
80 | // streams(RPCs). If false, and client sends ping when there are no active | ||
81 | // streams, server will send GOAWAY and close the connection. | ||
64 | PermitWithoutStream bool // false by default. | 82 | PermitWithoutStream bool // false by default. |
65 | } | 83 | } |
diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index be4f9e7..cf6d1b9 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go | |||
@@ -17,17 +17,19 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | // Package metadata define the structure of the metadata supported by gRPC library. | 19 | // Package metadata define the structure of the metadata supported by gRPC library. |
20 | // Please refer to https://grpc.io/docs/guides/wire.html for more information about custom-metadata. | 20 | // Please refer to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md |
21 | // for more information about custom-metadata. | ||
21 | package metadata // import "google.golang.org/grpc/metadata" | 22 | package metadata // import "google.golang.org/grpc/metadata" |
22 | 23 | ||
23 | import ( | 24 | import ( |
25 | "context" | ||
24 | "fmt" | 26 | "fmt" |
25 | "strings" | 27 | "strings" |
26 | |||
27 | "golang.org/x/net/context" | ||
28 | ) | 28 | ) |
29 | 29 | ||
30 | // DecodeKeyValue returns k, v, nil. It is deprecated and should not be used. | 30 | // DecodeKeyValue returns k, v, nil. |
31 | // | ||
32 | // Deprecated: use k and v directly instead. | ||
31 | func DecodeKeyValue(k, v string) (string, string, error) { | 33 | func DecodeKeyValue(k, v string) (string, string, error) { |
32 | return k, v, nil | 34 | return k, v, nil |
33 | } | 35 | } |
@@ -44,6 +46,9 @@ type MD map[string][]string | |||
44 | // - lowercase letters: a-z | 46 | // - lowercase letters: a-z |
45 | // - special characters: -_. | 47 | // - special characters: -_. |
46 | // Uppercase letters are automatically converted to lowercase. | 48 | // Uppercase letters are automatically converted to lowercase. |
49 | // | ||
50 | // Keys beginning with "grpc-" are reserved for grpc-internal use only and may | ||
51 | // result in errors if set in metadata. | ||
47 | func New(m map[string]string) MD { | 52 | func New(m map[string]string) MD { |
48 | md := MD{} | 53 | md := MD{} |
49 | for k, val := range m { | 54 | for k, val := range m { |
@@ -62,6 +67,9 @@ func New(m map[string]string) MD { | |||
62 | // - lowercase letters: a-z | 67 | // - lowercase letters: a-z |
63 | // - special characters: -_. | 68 | // - special characters: -_. |
64 | // Uppercase letters are automatically converted to lowercase. | 69 | // Uppercase letters are automatically converted to lowercase. |
70 | // | ||
71 | // Keys beginning with "grpc-" are reserved for grpc-internal use only and may | ||
72 | // result in errors if set in metadata. | ||
65 | func Pairs(kv ...string) MD { | 73 | func Pairs(kv ...string) MD { |
66 | if len(kv)%2 == 1 { | 74 | if len(kv)%2 == 1 { |
67 | panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) | 75 | panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) |
@@ -88,6 +96,30 @@ func (md MD) Copy() MD { | |||
88 | return Join(md) | 96 | return Join(md) |
89 | } | 97 | } |
90 | 98 | ||
99 | // Get obtains the values for a given key. | ||
100 | func (md MD) Get(k string) []string { | ||
101 | k = strings.ToLower(k) | ||
102 | return md[k] | ||
103 | } | ||
104 | |||
105 | // Set sets the value of a given key with a slice of values. | ||
106 | func (md MD) Set(k string, vals ...string) { | ||
107 | if len(vals) == 0 { | ||
108 | return | ||
109 | } | ||
110 | k = strings.ToLower(k) | ||
111 | md[k] = vals | ||
112 | } | ||
113 | |||
114 | // Append adds the values to key k, not overwriting what was already stored at that key. | ||
115 | func (md MD) Append(k string, vals ...string) { | ||
116 | if len(vals) == 0 { | ||
117 | return | ||
118 | } | ||
119 | k = strings.ToLower(k) | ||
120 | md[k] = append(md[k], vals...) | ||
121 | } | ||
122 | |||
91 | // Join joins any number of mds into a single MD. | 123 | // Join joins any number of mds into a single MD. |
92 | // The order of values for each key is determined by the order in which | 124 | // The order of values for each key is determined by the order in which |
93 | // the mds containing those values are presented to Join. | 125 | // the mds containing those values are presented to Join. |
@@ -104,24 +136,31 @@ func Join(mds ...MD) MD { | |||
104 | type mdIncomingKey struct{} | 136 | type mdIncomingKey struct{} |
105 | type mdOutgoingKey struct{} | 137 | type mdOutgoingKey struct{} |
106 | 138 | ||
107 | // NewContext is a wrapper for NewOutgoingContext(ctx, md). Deprecated. | ||
108 | func NewContext(ctx context.Context, md MD) context.Context { | ||
109 | return NewOutgoingContext(ctx, md) | ||
110 | } | ||
111 | |||
112 | // NewIncomingContext creates a new context with incoming md attached. | 139 | // NewIncomingContext creates a new context with incoming md attached. |
113 | func NewIncomingContext(ctx context.Context, md MD) context.Context { | 140 | func NewIncomingContext(ctx context.Context, md MD) context.Context { |
114 | return context.WithValue(ctx, mdIncomingKey{}, md) | 141 | return context.WithValue(ctx, mdIncomingKey{}, md) |
115 | } | 142 | } |
116 | 143 | ||
117 | // NewOutgoingContext creates a new context with outgoing md attached. | 144 | // NewOutgoingContext creates a new context with outgoing md attached. If used |
145 | // in conjunction with AppendToOutgoingContext, NewOutgoingContext will | ||
146 | // overwrite any previously-appended metadata. | ||
118 | func NewOutgoingContext(ctx context.Context, md MD) context.Context { | 147 | func NewOutgoingContext(ctx context.Context, md MD) context.Context { |
119 | return context.WithValue(ctx, mdOutgoingKey{}, md) | 148 | return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md}) |
120 | } | 149 | } |
121 | 150 | ||
122 | // FromContext is a wrapper for FromIncomingContext(ctx). Deprecated. | 151 | // AppendToOutgoingContext returns a new context with the provided kv merged |
123 | func FromContext(ctx context.Context) (md MD, ok bool) { | 152 | // with any existing metadata in the context. Please refer to the |
124 | return FromIncomingContext(ctx) | 153 | // documentation of Pairs for a description of kv. |
154 | func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context { | ||
155 | if len(kv)%2 == 1 { | ||
156 | panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) | ||
157 | } | ||
158 | md, _ := ctx.Value(mdOutgoingKey{}).(rawMD) | ||
159 | added := make([][]string, len(md.added)+1) | ||
160 | copy(added, md.added) | ||
161 | added[len(added)-1] = make([]string, len(kv)) | ||
162 | copy(added[len(added)-1], kv) | ||
163 | return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added}) | ||
125 | } | 164 | } |
126 | 165 | ||
127 | // FromIncomingContext returns the incoming metadata in ctx if it exists. The | 166 | // FromIncomingContext returns the incoming metadata in ctx if it exists. The |
@@ -132,10 +171,39 @@ func FromIncomingContext(ctx context.Context) (md MD, ok bool) { | |||
132 | return | 171 | return |
133 | } | 172 | } |
134 | 173 | ||
174 | // FromOutgoingContextRaw returns the un-merged, intermediary contents | ||
175 | // of rawMD. Remember to perform strings.ToLower on the keys. The returned | ||
176 | // MD should not be modified. Writing to it may cause races. Modification | ||
177 | // should be made to copies of the returned MD. | ||
178 | // | ||
179 | // This is intended for gRPC-internal use ONLY. | ||
180 | func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { | ||
181 | raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) | ||
182 | if !ok { | ||
183 | return nil, nil, false | ||
184 | } | ||
185 | |||
186 | return raw.md, raw.added, true | ||
187 | } | ||
188 | |||
135 | // FromOutgoingContext returns the outgoing metadata in ctx if it exists. The | 189 | // FromOutgoingContext returns the outgoing metadata in ctx if it exists. The |
136 | // returned MD should not be modified. Writing to it may cause races. | 190 | // returned MD should not be modified. Writing to it may cause races. |
137 | // Modification should be made to the copies of the returned MD. | 191 | // Modification should be made to copies of the returned MD. |
138 | func FromOutgoingContext(ctx context.Context) (md MD, ok bool) { | 192 | func FromOutgoingContext(ctx context.Context) (MD, bool) { |
139 | md, ok = ctx.Value(mdOutgoingKey{}).(MD) | 193 | raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) |
140 | return | 194 | if !ok { |
195 | return nil, false | ||
196 | } | ||
197 | |||
198 | mds := make([]MD, 0, len(raw.added)+1) | ||
199 | mds = append(mds, raw.md) | ||
200 | for _, vv := range raw.added { | ||
201 | mds = append(mds, Pairs(vv...)) | ||
202 | } | ||
203 | return Join(mds...), ok | ||
204 | } | ||
205 | |||
206 | type rawMD struct { | ||
207 | md MD | ||
208 | added [][]string | ||
141 | } | 209 | } |
diff --git a/vendor/google.golang.org/grpc/naming/dns_resolver.go b/vendor/google.golang.org/grpc/naming/dns_resolver.go index efd37e3..fd8cd3b 100644 --- a/vendor/google.golang.org/grpc/naming/dns_resolver.go +++ b/vendor/google.golang.org/grpc/naming/dns_resolver.go | |||
@@ -19,13 +19,13 @@ | |||
19 | package naming | 19 | package naming |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "context" | ||
22 | "errors" | 23 | "errors" |
23 | "fmt" | 24 | "fmt" |
24 | "net" | 25 | "net" |
25 | "strconv" | 26 | "strconv" |
26 | "time" | 27 | "time" |
27 | 28 | ||
28 | "golang.org/x/net/context" | ||
29 | "google.golang.org/grpc/grpclog" | 29 | "google.golang.org/grpc/grpclog" |
30 | ) | 30 | ) |
31 | 31 | ||
@@ -37,6 +37,9 @@ const ( | |||
37 | var ( | 37 | var ( |
38 | errMissingAddr = errors.New("missing address") | 38 | errMissingAddr = errors.New("missing address") |
39 | errWatcherClose = errors.New("watcher has been closed") | 39 | errWatcherClose = errors.New("watcher has been closed") |
40 | |||
41 | lookupHost = net.DefaultResolver.LookupHost | ||
42 | lookupSRV = net.DefaultResolver.LookupSRV | ||
40 | ) | 43 | ) |
41 | 44 | ||
42 | // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and | 45 | // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and |
@@ -141,8 +144,8 @@ type dnsWatcher struct { | |||
141 | r *dnsResolver | 144 | r *dnsResolver |
142 | host string | 145 | host string |
143 | port string | 146 | port string |
144 | // The latest resolved address list | 147 | // The latest resolved address set |
145 | curAddrs []*Update | 148 | curAddrs map[string]*Update |
146 | ctx context.Context | 149 | ctx context.Context |
147 | cancel context.CancelFunc | 150 | cancel context.CancelFunc |
148 | t *time.Timer | 151 | t *time.Timer |
@@ -153,10 +156,10 @@ type ipWatcher struct { | |||
153 | updateChan chan *Update | 156 | updateChan chan *Update |
154 | } | 157 | } |
155 | 158 | ||
156 | // Next returns the adrress resolution Update for the target. For IP address, | 159 | // Next returns the address resolution Update for the target. For IP address, |
157 | // the resolution is itself, thus polling name server is unncessary. Therefore, | 160 | // the resolution is itself, thus polling name server is unnecessary. Therefore, |
158 | // Next() will return an Update the first time it is called, and will be blocked | 161 | // Next() will return an Update the first time it is called, and will be blocked |
159 | // for all following calls as no Update exisits until watcher is closed. | 162 | // for all following calls as no Update exists until watcher is closed. |
160 | func (i *ipWatcher) Next() ([]*Update, error) { | 163 | func (i *ipWatcher) Next() ([]*Update, error) { |
161 | u, ok := <-i.updateChan | 164 | u, ok := <-i.updateChan |
162 | if !ok { | 165 | if !ok { |
@@ -192,28 +195,24 @@ type AddrMetadataGRPCLB struct { | |||
192 | 195 | ||
193 | // compileUpdate compares the old resolved addresses and newly resolved addresses, | 196 | // compileUpdate compares the old resolved addresses and newly resolved addresses, |
194 | // and generates an update list | 197 | // and generates an update list |
195 | func (w *dnsWatcher) compileUpdate(newAddrs []*Update) []*Update { | 198 | func (w *dnsWatcher) compileUpdate(newAddrs map[string]*Update) []*Update { |
196 | update := make(map[Update]bool) | 199 | var res []*Update |
197 | for _, u := range newAddrs { | 200 | for a, u := range w.curAddrs { |
198 | update[*u] = true | 201 | if _, ok := newAddrs[a]; !ok { |
199 | } | 202 | u.Op = Delete |
200 | for _, u := range w.curAddrs { | 203 | res = append(res, u) |
201 | if _, ok := update[*u]; ok { | ||
202 | delete(update, *u) | ||
203 | continue | ||
204 | } | 204 | } |
205 | update[Update{Addr: u.Addr, Op: Delete, Metadata: u.Metadata}] = true | ||
206 | } | 205 | } |
207 | res := make([]*Update, 0, len(update)) | 206 | for a, u := range newAddrs { |
208 | for k := range update { | 207 | if _, ok := w.curAddrs[a]; !ok { |
209 | tmp := k | 208 | res = append(res, u) |
210 | res = append(res, &tmp) | 209 | } |
211 | } | 210 | } |
212 | return res | 211 | return res |
213 | } | 212 | } |
214 | 213 | ||
215 | func (w *dnsWatcher) lookupSRV() []*Update { | 214 | func (w *dnsWatcher) lookupSRV() map[string]*Update { |
216 | var newAddrs []*Update | 215 | newAddrs := make(map[string]*Update) |
217 | _, srvs, err := lookupSRV(w.ctx, "grpclb", "tcp", w.host) | 216 | _, srvs, err := lookupSRV(w.ctx, "grpclb", "tcp", w.host) |
218 | if err != nil { | 217 | if err != nil { |
219 | grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err) | 218 | grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err) |
@@ -231,15 +230,16 @@ func (w *dnsWatcher) lookupSRV() []*Update { | |||
231 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) | 230 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) |
232 | continue | 231 | continue |
233 | } | 232 | } |
234 | newAddrs = append(newAddrs, &Update{Addr: a + ":" + strconv.Itoa(int(s.Port)), | 233 | addr := a + ":" + strconv.Itoa(int(s.Port)) |
235 | Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: s.Target}}) | 234 | newAddrs[addr] = &Update{Addr: addr, |
235 | Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: s.Target}} | ||
236 | } | 236 | } |
237 | } | 237 | } |
238 | return newAddrs | 238 | return newAddrs |
239 | } | 239 | } |
240 | 240 | ||
241 | func (w *dnsWatcher) lookupHost() []*Update { | 241 | func (w *dnsWatcher) lookupHost() map[string]*Update { |
242 | var newAddrs []*Update | 242 | newAddrs := make(map[string]*Update) |
243 | addrs, err := lookupHost(w.ctx, w.host) | 243 | addrs, err := lookupHost(w.ctx, w.host) |
244 | if err != nil { | 244 | if err != nil { |
245 | grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err) | 245 | grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err) |
@@ -251,7 +251,8 @@ func (w *dnsWatcher) lookupHost() []*Update { | |||
251 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) | 251 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) |
252 | continue | 252 | continue |
253 | } | 253 | } |
254 | newAddrs = append(newAddrs, &Update{Addr: a + ":" + w.port}) | 254 | addr := a + ":" + w.port |
255 | newAddrs[addr] = &Update{Addr: addr} | ||
255 | } | 256 | } |
256 | return newAddrs | 257 | return newAddrs |
257 | } | 258 | } |
diff --git a/vendor/google.golang.org/grpc/naming/naming.go b/vendor/google.golang.org/grpc/naming/naming.go index 1af7e32..8cc39e9 100644 --- a/vendor/google.golang.org/grpc/naming/naming.go +++ b/vendor/google.golang.org/grpc/naming/naming.go | |||
@@ -18,20 +18,26 @@ | |||
18 | 18 | ||
19 | // Package naming defines the naming API and related data structures for gRPC. | 19 | // Package naming defines the naming API and related data structures for gRPC. |
20 | // The interface is EXPERIMENTAL and may be suject to change. | 20 | // The interface is EXPERIMENTAL and may be suject to change. |
21 | // | ||
22 | // Deprecated: please use package resolver. | ||
21 | package naming | 23 | package naming |
22 | 24 | ||
23 | // Operation defines the corresponding operations for a name resolution change. | 25 | // Operation defines the corresponding operations for a name resolution change. |
26 | // | ||
27 | // Deprecated: please use package resolver. | ||
24 | type Operation uint8 | 28 | type Operation uint8 |
25 | 29 | ||
26 | const ( | 30 | const ( |
27 | // Add indicates a new address is added. | 31 | // Add indicates a new address is added. |
28 | Add Operation = iota | 32 | Add Operation = iota |
29 | // Delete indicates an exisiting address is deleted. | 33 | // Delete indicates an existing address is deleted. |
30 | Delete | 34 | Delete |
31 | ) | 35 | ) |
32 | 36 | ||
33 | // Update defines a name resolution update. Notice that it is not valid having both | 37 | // Update defines a name resolution update. Notice that it is not valid having both |
34 | // empty string Addr and nil Metadata in an Update. | 38 | // empty string Addr and nil Metadata in an Update. |
39 | // | ||
40 | // Deprecated: please use package resolver. | ||
35 | type Update struct { | 41 | type Update struct { |
36 | // Op indicates the operation of the update. | 42 | // Op indicates the operation of the update. |
37 | Op Operation | 43 | Op Operation |
@@ -43,12 +49,16 @@ type Update struct { | |||
43 | } | 49 | } |
44 | 50 | ||
45 | // Resolver creates a Watcher for a target to track its resolution changes. | 51 | // Resolver creates a Watcher for a target to track its resolution changes. |
52 | // | ||
53 | // Deprecated: please use package resolver. | ||
46 | type Resolver interface { | 54 | type Resolver interface { |
47 | // Resolve creates a Watcher for target. | 55 | // Resolve creates a Watcher for target. |
48 | Resolve(target string) (Watcher, error) | 56 | Resolve(target string) (Watcher, error) |
49 | } | 57 | } |
50 | 58 | ||
51 | // Watcher watches for the updates on the specified target. | 59 | // Watcher watches for the updates on the specified target. |
60 | // | ||
61 | // Deprecated: please use package resolver. | ||
52 | type Watcher interface { | 62 | type Watcher interface { |
53 | // Next blocks until an update or error happens. It may return one or more | 63 | // Next blocks until an update or error happens. It may return one or more |
54 | // updates. The first call should get the full set of the results. It should | 64 | // updates. The first call should get the full set of the results. It should |
diff --git a/vendor/google.golang.org/grpc/peer/peer.go b/vendor/google.golang.org/grpc/peer/peer.go index 317b8b9..e01d219 100644 --- a/vendor/google.golang.org/grpc/peer/peer.go +++ b/vendor/google.golang.org/grpc/peer/peer.go | |||
@@ -21,9 +21,9 @@ | |||
21 | package peer | 21 | package peer |
22 | 22 | ||
23 | import ( | 23 | import ( |
24 | "context" | ||
24 | "net" | 25 | "net" |
25 | 26 | ||
26 | "golang.org/x/net/context" | ||
27 | "google.golang.org/grpc/credentials" | 27 | "google.golang.org/grpc/credentials" |
28 | ) | 28 | ) |
29 | 29 | ||
diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go new file mode 100644 index 0000000..14f915d --- /dev/null +++ b/vendor/google.golang.org/grpc/picker_wrapper.go | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | "io" | ||
24 | "sync" | ||
25 | |||
26 | "google.golang.org/grpc/balancer" | ||
27 | "google.golang.org/grpc/codes" | ||
28 | "google.golang.org/grpc/grpclog" | ||
29 | "google.golang.org/grpc/internal/channelz" | ||
30 | "google.golang.org/grpc/internal/transport" | ||
31 | "google.golang.org/grpc/status" | ||
32 | ) | ||
33 | |||
34 | // pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick | ||
35 | // actions and unblock when there's a picker update. | ||
36 | type pickerWrapper struct { | ||
37 | mu sync.Mutex | ||
38 | done bool | ||
39 | blockingCh chan struct{} | ||
40 | picker balancer.Picker | ||
41 | |||
42 | // The latest connection happened. | ||
43 | connErrMu sync.Mutex | ||
44 | connErr error | ||
45 | } | ||
46 | |||
47 | func newPickerWrapper() *pickerWrapper { | ||
48 | bp := &pickerWrapper{blockingCh: make(chan struct{})} | ||
49 | return bp | ||
50 | } | ||
51 | |||
52 | func (bp *pickerWrapper) updateConnectionError(err error) { | ||
53 | bp.connErrMu.Lock() | ||
54 | bp.connErr = err | ||
55 | bp.connErrMu.Unlock() | ||
56 | } | ||
57 | |||
58 | func (bp *pickerWrapper) connectionError() error { | ||
59 | bp.connErrMu.Lock() | ||
60 | err := bp.connErr | ||
61 | bp.connErrMu.Unlock() | ||
62 | return err | ||
63 | } | ||
64 | |||
65 | // updatePicker is called by UpdateBalancerState. It unblocks all blocked pick. | ||
66 | func (bp *pickerWrapper) updatePicker(p balancer.Picker) { | ||
67 | bp.mu.Lock() | ||
68 | if bp.done { | ||
69 | bp.mu.Unlock() | ||
70 | return | ||
71 | } | ||
72 | bp.picker = p | ||
73 | // bp.blockingCh should never be nil. | ||
74 | close(bp.blockingCh) | ||
75 | bp.blockingCh = make(chan struct{}) | ||
76 | bp.mu.Unlock() | ||
77 | } | ||
78 | |||
79 | func doneChannelzWrapper(acw *acBalancerWrapper, done func(balancer.DoneInfo)) func(balancer.DoneInfo) { | ||
80 | acw.mu.Lock() | ||
81 | ac := acw.ac | ||
82 | acw.mu.Unlock() | ||
83 | ac.incrCallsStarted() | ||
84 | return func(b balancer.DoneInfo) { | ||
85 | if b.Err != nil && b.Err != io.EOF { | ||
86 | ac.incrCallsFailed() | ||
87 | } else { | ||
88 | ac.incrCallsSucceeded() | ||
89 | } | ||
90 | if done != nil { | ||
91 | done(b) | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | // pick returns the transport that will be used for the RPC. | ||
97 | // It may block in the following cases: | ||
98 | // - there's no picker | ||
99 | // - the current picker returns ErrNoSubConnAvailable | ||
100 | // - the current picker returns other errors and failfast is false. | ||
101 | // - the subConn returned by the current picker is not READY | ||
102 | // When one of these situations happens, pick blocks until the picker gets updated. | ||
103 | func (bp *pickerWrapper) pick(ctx context.Context, failfast bool, opts balancer.PickOptions) (transport.ClientTransport, func(balancer.DoneInfo), error) { | ||
104 | var ( | ||
105 | p balancer.Picker | ||
106 | ch chan struct{} | ||
107 | ) | ||
108 | |||
109 | for { | ||
110 | bp.mu.Lock() | ||
111 | if bp.done { | ||
112 | bp.mu.Unlock() | ||
113 | return nil, nil, ErrClientConnClosing | ||
114 | } | ||
115 | |||
116 | if bp.picker == nil { | ||
117 | ch = bp.blockingCh | ||
118 | } | ||
119 | if ch == bp.blockingCh { | ||
120 | // This could happen when either: | ||
121 | // - bp.picker is nil (the previous if condition), or | ||
122 | // - has called pick on the current picker. | ||
123 | bp.mu.Unlock() | ||
124 | select { | ||
125 | case <-ctx.Done(): | ||
126 | return nil, nil, ctx.Err() | ||
127 | case <-ch: | ||
128 | } | ||
129 | continue | ||
130 | } | ||
131 | |||
132 | ch = bp.blockingCh | ||
133 | p = bp.picker | ||
134 | bp.mu.Unlock() | ||
135 | |||
136 | subConn, done, err := p.Pick(ctx, opts) | ||
137 | |||
138 | if err != nil { | ||
139 | switch err { | ||
140 | case balancer.ErrNoSubConnAvailable: | ||
141 | continue | ||
142 | case balancer.ErrTransientFailure: | ||
143 | if !failfast { | ||
144 | continue | ||
145 | } | ||
146 | return nil, nil, status.Errorf(codes.Unavailable, "%v, latest connection error: %v", err, bp.connectionError()) | ||
147 | default: | ||
148 | // err is some other error. | ||
149 | return nil, nil, toRPCErr(err) | ||
150 | } | ||
151 | } | ||
152 | |||
153 | acw, ok := subConn.(*acBalancerWrapper) | ||
154 | if !ok { | ||
155 | grpclog.Infof("subconn returned from pick is not *acBalancerWrapper") | ||
156 | continue | ||
157 | } | ||
158 | if t, ok := acw.getAddrConn().getReadyTransport(); ok { | ||
159 | if channelz.IsOn() { | ||
160 | return t, doneChannelzWrapper(acw, done), nil | ||
161 | } | ||
162 | return t, done, nil | ||
163 | } | ||
164 | grpclog.Infof("blockingPicker: the picked transport is not ready, loop back to repick") | ||
165 | // If ok == false, ac.state is not READY. | ||
166 | // A valid picker always returns READY subConn. This means the state of ac | ||
167 | // just changed, and picker will be updated shortly. | ||
168 | // continue back to the beginning of the for loop to repick. | ||
169 | } | ||
170 | } | ||
171 | |||
172 | func (bp *pickerWrapper) close() { | ||
173 | bp.mu.Lock() | ||
174 | defer bp.mu.Unlock() | ||
175 | if bp.done { | ||
176 | return | ||
177 | } | ||
178 | bp.done = true | ||
179 | close(bp.blockingCh) | ||
180 | } | ||
diff --git a/vendor/google.golang.org/grpc/pickfirst.go b/vendor/google.golang.org/grpc/pickfirst.go new file mode 100644 index 0000000..d1e38aa --- /dev/null +++ b/vendor/google.golang.org/grpc/pickfirst.go | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "context" | ||
23 | |||
24 | "google.golang.org/grpc/balancer" | ||
25 | "google.golang.org/grpc/connectivity" | ||
26 | "google.golang.org/grpc/grpclog" | ||
27 | "google.golang.org/grpc/resolver" | ||
28 | ) | ||
29 | |||
30 | // PickFirstBalancerName is the name of the pick_first balancer. | ||
31 | const PickFirstBalancerName = "pick_first" | ||
32 | |||
33 | func newPickfirstBuilder() balancer.Builder { | ||
34 | return &pickfirstBuilder{} | ||
35 | } | ||
36 | |||
37 | type pickfirstBuilder struct{} | ||
38 | |||
39 | func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { | ||
40 | return &pickfirstBalancer{cc: cc} | ||
41 | } | ||
42 | |||
43 | func (*pickfirstBuilder) Name() string { | ||
44 | return PickFirstBalancerName | ||
45 | } | ||
46 | |||
47 | type pickfirstBalancer struct { | ||
48 | cc balancer.ClientConn | ||
49 | sc balancer.SubConn | ||
50 | } | ||
51 | |||
52 | func (b *pickfirstBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) { | ||
53 | if err != nil { | ||
54 | grpclog.Infof("pickfirstBalancer: HandleResolvedAddrs called with error %v", err) | ||
55 | return | ||
56 | } | ||
57 | if b.sc == nil { | ||
58 | b.sc, err = b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{}) | ||
59 | if err != nil { | ||
60 | //TODO(yuxuanli): why not change the cc state to Idle? | ||
61 | grpclog.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err) | ||
62 | return | ||
63 | } | ||
64 | b.cc.UpdateBalancerState(connectivity.Idle, &picker{sc: b.sc}) | ||
65 | b.sc.Connect() | ||
66 | } else { | ||
67 | b.sc.UpdateAddresses(addrs) | ||
68 | b.sc.Connect() | ||
69 | } | ||
70 | } | ||
71 | |||
72 | func (b *pickfirstBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { | ||
73 | grpclog.Infof("pickfirstBalancer: HandleSubConnStateChange: %p, %v", sc, s) | ||
74 | if b.sc != sc { | ||
75 | grpclog.Infof("pickfirstBalancer: ignored state change because sc is not recognized") | ||
76 | return | ||
77 | } | ||
78 | if s == connectivity.Shutdown { | ||
79 | b.sc = nil | ||
80 | return | ||
81 | } | ||
82 | |||
83 | switch s { | ||
84 | case connectivity.Ready, connectivity.Idle: | ||
85 | b.cc.UpdateBalancerState(s, &picker{sc: sc}) | ||
86 | case connectivity.Connecting: | ||
87 | b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrNoSubConnAvailable}) | ||
88 | case connectivity.TransientFailure: | ||
89 | b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrTransientFailure}) | ||
90 | } | ||
91 | } | ||
92 | |||
93 | func (b *pickfirstBalancer) Close() { | ||
94 | } | ||
95 | |||
96 | type picker struct { | ||
97 | err error | ||
98 | sc balancer.SubConn | ||
99 | } | ||
100 | |||
101 | func (p *picker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) { | ||
102 | if p.err != nil { | ||
103 | return nil, nil, p.err | ||
104 | } | ||
105 | return p.sc, nil, nil | ||
106 | } | ||
107 | |||
108 | func init() { | ||
109 | balancer.Register(newPickfirstBuilder()) | ||
110 | } | ||
diff --git a/vendor/google.golang.org/grpc/proxy.go b/vendor/google.golang.org/grpc/proxy.go index 2d40236..f8f69bf 100644 --- a/vendor/google.golang.org/grpc/proxy.go +++ b/vendor/google.golang.org/grpc/proxy.go | |||
@@ -20,6 +20,8 @@ package grpc | |||
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "bufio" | 22 | "bufio" |
23 | "context" | ||
24 | "encoding/base64" | ||
23 | "errors" | 25 | "errors" |
24 | "fmt" | 26 | "fmt" |
25 | "io" | 27 | "io" |
@@ -27,10 +29,10 @@ import ( | |||
27 | "net/http" | 29 | "net/http" |
28 | "net/http/httputil" | 30 | "net/http/httputil" |
29 | "net/url" | 31 | "net/url" |
30 | |||
31 | "golang.org/x/net/context" | ||
32 | ) | 32 | ) |
33 | 33 | ||
34 | const proxyAuthHeaderKey = "Proxy-Authorization" | ||
35 | |||
34 | var ( | 36 | var ( |
35 | // errDisabled indicates that proxy is disabled for the address. | 37 | // errDisabled indicates that proxy is disabled for the address. |
36 | errDisabled = errors.New("proxy is disabled for the address") | 38 | errDisabled = errors.New("proxy is disabled for the address") |
@@ -38,7 +40,7 @@ var ( | |||
38 | httpProxyFromEnvironment = http.ProxyFromEnvironment | 40 | httpProxyFromEnvironment = http.ProxyFromEnvironment |
39 | ) | 41 | ) |
40 | 42 | ||
41 | func mapAddress(ctx context.Context, address string) (string, error) { | 43 | func mapAddress(ctx context.Context, address string) (*url.URL, error) { |
42 | req := &http.Request{ | 44 | req := &http.Request{ |
43 | URL: &url.URL{ | 45 | URL: &url.URL{ |
44 | Scheme: "https", | 46 | Scheme: "https", |
@@ -47,12 +49,12 @@ func mapAddress(ctx context.Context, address string) (string, error) { | |||
47 | } | 49 | } |
48 | url, err := httpProxyFromEnvironment(req) | 50 | url, err := httpProxyFromEnvironment(req) |
49 | if err != nil { | 51 | if err != nil { |
50 | return "", err | 52 | return nil, err |
51 | } | 53 | } |
52 | if url == nil { | 54 | if url == nil { |
53 | return "", errDisabled | 55 | return nil, errDisabled |
54 | } | 56 | } |
55 | return url.Host, nil | 57 | return url, nil |
56 | } | 58 | } |
57 | 59 | ||
58 | // To read a response from a net.Conn, http.ReadResponse() takes a bufio.Reader. | 60 | // To read a response from a net.Conn, http.ReadResponse() takes a bufio.Reader. |
@@ -69,18 +71,28 @@ func (c *bufConn) Read(b []byte) (int, error) { | |||
69 | return c.r.Read(b) | 71 | return c.r.Read(b) |
70 | } | 72 | } |
71 | 73 | ||
72 | func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, addr string) (_ net.Conn, err error) { | 74 | func basicAuth(username, password string) string { |
75 | auth := username + ":" + password | ||
76 | return base64.StdEncoding.EncodeToString([]byte(auth)) | ||
77 | } | ||
78 | |||
79 | func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, backendAddr string, proxyURL *url.URL) (_ net.Conn, err error) { | ||
73 | defer func() { | 80 | defer func() { |
74 | if err != nil { | 81 | if err != nil { |
75 | conn.Close() | 82 | conn.Close() |
76 | } | 83 | } |
77 | }() | 84 | }() |
78 | 85 | ||
79 | req := (&http.Request{ | 86 | req := &http.Request{ |
80 | Method: http.MethodConnect, | 87 | Method: http.MethodConnect, |
81 | URL: &url.URL{Host: addr}, | 88 | URL: &url.URL{Host: backendAddr}, |
82 | Header: map[string][]string{"User-Agent": {grpcUA}}, | 89 | Header: map[string][]string{"User-Agent": {grpcUA}}, |
83 | }) | 90 | } |
91 | if t := proxyURL.User; t != nil { | ||
92 | u := t.Username() | ||
93 | p, _ := t.Password() | ||
94 | req.Header.Add(proxyAuthHeaderKey, "Basic "+basicAuth(u, p)) | ||
95 | } | ||
84 | 96 | ||
85 | if err := sendHTTPRequest(ctx, req, conn); err != nil { | 97 | if err := sendHTTPRequest(ctx, req, conn); err != nil { |
86 | return nil, fmt.Errorf("failed to write the HTTP request: %v", err) | 98 | return nil, fmt.Errorf("failed to write the HTTP request: %v", err) |
@@ -108,23 +120,33 @@ func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, addr string) (_ | |||
108 | // provided dialer, does HTTP CONNECT handshake and returns the connection. | 120 | // provided dialer, does HTTP CONNECT handshake and returns the connection. |
109 | func newProxyDialer(dialer func(context.Context, string) (net.Conn, error)) func(context.Context, string) (net.Conn, error) { | 121 | func newProxyDialer(dialer func(context.Context, string) (net.Conn, error)) func(context.Context, string) (net.Conn, error) { |
110 | return func(ctx context.Context, addr string) (conn net.Conn, err error) { | 122 | return func(ctx context.Context, addr string) (conn net.Conn, err error) { |
111 | var skipHandshake bool | 123 | var newAddr string |
112 | newAddr, err := mapAddress(ctx, addr) | 124 | proxyURL, err := mapAddress(ctx, addr) |
113 | if err != nil { | 125 | if err != nil { |
114 | if err != errDisabled { | 126 | if err != errDisabled { |
115 | return nil, err | 127 | return nil, err |
116 | } | 128 | } |
117 | skipHandshake = true | ||
118 | newAddr = addr | 129 | newAddr = addr |
130 | } else { | ||
131 | newAddr = proxyURL.Host | ||
119 | } | 132 | } |
120 | 133 | ||
121 | conn, err = dialer(ctx, newAddr) | 134 | conn, err = dialer(ctx, newAddr) |
122 | if err != nil { | 135 | if err != nil { |
123 | return | 136 | return |
124 | } | 137 | } |
125 | if !skipHandshake { | 138 | if proxyURL != nil { |
126 | conn, err = doHTTPConnectHandshake(ctx, conn, addr) | 139 | // proxy is disabled if proxyURL is nil. |
140 | conn, err = doHTTPConnectHandshake(ctx, conn, addr, proxyURL) | ||
127 | } | 141 | } |
128 | return | 142 | return |
129 | } | 143 | } |
130 | } | 144 | } |
145 | |||
146 | func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { | ||
147 | req = req.WithContext(ctx) | ||
148 | if err := req.Write(conn); err != nil { | ||
149 | return fmt.Errorf("failed to write the HTTP request: %v", err) | ||
150 | } | ||
151 | return nil | ||
152 | } | ||
diff --git a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go new file mode 100644 index 0000000..f33189f --- /dev/null +++ b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2018 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package dns implements a dns resolver to be installed as the default resolver | ||
20 | // in grpc. | ||
21 | package dns | ||
22 | |||
23 | import ( | ||
24 | "context" | ||
25 | "encoding/json" | ||
26 | "errors" | ||
27 | "fmt" | ||
28 | "net" | ||
29 | "os" | ||
30 | "strconv" | ||
31 | "strings" | ||
32 | "sync" | ||
33 | "time" | ||
34 | |||
35 | "google.golang.org/grpc/grpclog" | ||
36 | "google.golang.org/grpc/internal/backoff" | ||
37 | "google.golang.org/grpc/internal/grpcrand" | ||
38 | "google.golang.org/grpc/resolver" | ||
39 | ) | ||
40 | |||
41 | func init() { | ||
42 | resolver.Register(NewBuilder()) | ||
43 | } | ||
44 | |||
45 | const ( | ||
46 | defaultPort = "443" | ||
47 | defaultFreq = time.Minute * 30 | ||
48 | defaultDNSSvrPort = "53" | ||
49 | golang = "GO" | ||
50 | // In DNS, service config is encoded in a TXT record via the mechanism | ||
51 | // described in RFC-1464 using the attribute name grpc_config. | ||
52 | txtAttribute = "grpc_config=" | ||
53 | ) | ||
54 | |||
55 | var ( | ||
56 | errMissingAddr = errors.New("dns resolver: missing address") | ||
57 | |||
58 | // Addresses ending with a colon that is supposed to be the separator | ||
59 | // between host and port is not allowed. E.g. "::" is a valid address as | ||
60 | // it is an IPv6 address (host only) and "[::]:" is invalid as it ends with | ||
61 | // a colon as the host and port separator | ||
62 | errEndsWithColon = errors.New("dns resolver: missing port after port-separator colon") | ||
63 | ) | ||
64 | |||
65 | var ( | ||
66 | defaultResolver netResolver = net.DefaultResolver | ||
67 | ) | ||
68 | |||
69 | var customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) { | ||
70 | return func(ctx context.Context, network, address string) (net.Conn, error) { | ||
71 | var dialer net.Dialer | ||
72 | return dialer.DialContext(ctx, network, authority) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | var customAuthorityResolver = func(authority string) (netResolver, error) { | ||
77 | host, port, err := parseTarget(authority, defaultDNSSvrPort) | ||
78 | if err != nil { | ||
79 | return nil, err | ||
80 | } | ||
81 | |||
82 | authorityWithPort := net.JoinHostPort(host, port) | ||
83 | |||
84 | return &net.Resolver{ | ||
85 | PreferGo: true, | ||
86 | Dial: customAuthorityDialler(authorityWithPort), | ||
87 | }, nil | ||
88 | } | ||
89 | |||
90 | // NewBuilder creates a dnsBuilder which is used to factory DNS resolvers. | ||
91 | func NewBuilder() resolver.Builder { | ||
92 | return &dnsBuilder{minFreq: defaultFreq} | ||
93 | } | ||
94 | |||
95 | type dnsBuilder struct { | ||
96 | // minimum frequency of polling the DNS server. | ||
97 | minFreq time.Duration | ||
98 | } | ||
99 | |||
100 | // Build creates and starts a DNS resolver that watches the name resolution of the target. | ||
101 | func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) { | ||
102 | host, port, err := parseTarget(target.Endpoint, defaultPort) | ||
103 | if err != nil { | ||
104 | return nil, err | ||
105 | } | ||
106 | |||
107 | // IP address. | ||
108 | if net.ParseIP(host) != nil { | ||
109 | host, _ = formatIP(host) | ||
110 | addr := []resolver.Address{{Addr: host + ":" + port}} | ||
111 | i := &ipResolver{ | ||
112 | cc: cc, | ||
113 | ip: addr, | ||
114 | rn: make(chan struct{}, 1), | ||
115 | q: make(chan struct{}), | ||
116 | } | ||
117 | cc.NewAddress(addr) | ||
118 | go i.watcher() | ||
119 | return i, nil | ||
120 | } | ||
121 | |||
122 | // DNS address (non-IP). | ||
123 | ctx, cancel := context.WithCancel(context.Background()) | ||
124 | d := &dnsResolver{ | ||
125 | freq: b.minFreq, | ||
126 | backoff: backoff.Exponential{MaxDelay: b.minFreq}, | ||
127 | host: host, | ||
128 | port: port, | ||
129 | ctx: ctx, | ||
130 | cancel: cancel, | ||
131 | cc: cc, | ||
132 | t: time.NewTimer(0), | ||
133 | rn: make(chan struct{}, 1), | ||
134 | disableServiceConfig: opts.DisableServiceConfig, | ||
135 | } | ||
136 | |||
137 | if target.Authority == "" { | ||
138 | d.resolver = defaultResolver | ||
139 | } else { | ||
140 | d.resolver, err = customAuthorityResolver(target.Authority) | ||
141 | if err != nil { | ||
142 | return nil, err | ||
143 | } | ||
144 | } | ||
145 | |||
146 | d.wg.Add(1) | ||
147 | go d.watcher() | ||
148 | return d, nil | ||
149 | } | ||
150 | |||
151 | // Scheme returns the naming scheme of this resolver builder, which is "dns". | ||
152 | func (b *dnsBuilder) Scheme() string { | ||
153 | return "dns" | ||
154 | } | ||
155 | |||
156 | type netResolver interface { | ||
157 | LookupHost(ctx context.Context, host string) (addrs []string, err error) | ||
158 | LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) | ||
159 | LookupTXT(ctx context.Context, name string) (txts []string, err error) | ||
160 | } | ||
161 | |||
162 | // ipResolver watches for the name resolution update for an IP address. | ||
163 | type ipResolver struct { | ||
164 | cc resolver.ClientConn | ||
165 | ip []resolver.Address | ||
166 | // rn channel is used by ResolveNow() to force an immediate resolution of the target. | ||
167 | rn chan struct{} | ||
168 | q chan struct{} | ||
169 | } | ||
170 | |||
171 | // ResolveNow resend the address it stores, no resolution is needed. | ||
172 | func (i *ipResolver) ResolveNow(opt resolver.ResolveNowOption) { | ||
173 | select { | ||
174 | case i.rn <- struct{}{}: | ||
175 | default: | ||
176 | } | ||
177 | } | ||
178 | |||
179 | // Close closes the ipResolver. | ||
180 | func (i *ipResolver) Close() { | ||
181 | close(i.q) | ||
182 | } | ||
183 | |||
184 | func (i *ipResolver) watcher() { | ||
185 | for { | ||
186 | select { | ||
187 | case <-i.rn: | ||
188 | i.cc.NewAddress(i.ip) | ||
189 | case <-i.q: | ||
190 | return | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | // dnsResolver watches for the name resolution update for a non-IP target. | ||
196 | type dnsResolver struct { | ||
197 | freq time.Duration | ||
198 | backoff backoff.Exponential | ||
199 | retryCount int | ||
200 | host string | ||
201 | port string | ||
202 | resolver netResolver | ||
203 | ctx context.Context | ||
204 | cancel context.CancelFunc | ||
205 | cc resolver.ClientConn | ||
206 | // rn channel is used by ResolveNow() to force an immediate resolution of the target. | ||
207 | rn chan struct{} | ||
208 | t *time.Timer | ||
209 | // wg is used to enforce Close() to return after the watcher() goroutine has finished. | ||
210 | // Otherwise, data race will be possible. [Race Example] in dns_resolver_test we | ||
211 | // replace the real lookup functions with mocked ones to facilitate testing. | ||
212 | // If Close() doesn't wait for watcher() goroutine finishes, race detector sometimes | ||
213 | // will warns lookup (READ the lookup function pointers) inside watcher() goroutine | ||
214 | // has data race with replaceNetFunc (WRITE the lookup function pointers). | ||
215 | wg sync.WaitGroup | ||
216 | disableServiceConfig bool | ||
217 | } | ||
218 | |||
219 | // ResolveNow invoke an immediate resolution of the target that this dnsResolver watches. | ||
220 | func (d *dnsResolver) ResolveNow(opt resolver.ResolveNowOption) { | ||
221 | select { | ||
222 | case d.rn <- struct{}{}: | ||
223 | default: | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // Close closes the dnsResolver. | ||
228 | func (d *dnsResolver) Close() { | ||
229 | d.cancel() | ||
230 | d.wg.Wait() | ||
231 | d.t.Stop() | ||
232 | } | ||
233 | |||
234 | func (d *dnsResolver) watcher() { | ||
235 | defer d.wg.Done() | ||
236 | for { | ||
237 | select { | ||
238 | case <-d.ctx.Done(): | ||
239 | return | ||
240 | case <-d.t.C: | ||
241 | case <-d.rn: | ||
242 | } | ||
243 | result, sc := d.lookup() | ||
244 | // Next lookup should happen within an interval defined by d.freq. It may be | ||
245 | // more often due to exponential retry on empty address list. | ||
246 | if len(result) == 0 { | ||
247 | d.retryCount++ | ||
248 | d.t.Reset(d.backoff.Backoff(d.retryCount)) | ||
249 | } else { | ||
250 | d.retryCount = 0 | ||
251 | d.t.Reset(d.freq) | ||
252 | } | ||
253 | d.cc.NewServiceConfig(sc) | ||
254 | d.cc.NewAddress(result) | ||
255 | } | ||
256 | } | ||
257 | |||
258 | func (d *dnsResolver) lookupSRV() []resolver.Address { | ||
259 | var newAddrs []resolver.Address | ||
260 | _, srvs, err := d.resolver.LookupSRV(d.ctx, "grpclb", "tcp", d.host) | ||
261 | if err != nil { | ||
262 | grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err) | ||
263 | return nil | ||
264 | } | ||
265 | for _, s := range srvs { | ||
266 | lbAddrs, err := d.resolver.LookupHost(d.ctx, s.Target) | ||
267 | if err != nil { | ||
268 | grpclog.Infof("grpc: failed load balancer address dns lookup due to %v.\n", err) | ||
269 | continue | ||
270 | } | ||
271 | for _, a := range lbAddrs { | ||
272 | a, ok := formatIP(a) | ||
273 | if !ok { | ||
274 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) | ||
275 | continue | ||
276 | } | ||
277 | addr := a + ":" + strconv.Itoa(int(s.Port)) | ||
278 | newAddrs = append(newAddrs, resolver.Address{Addr: addr, Type: resolver.GRPCLB, ServerName: s.Target}) | ||
279 | } | ||
280 | } | ||
281 | return newAddrs | ||
282 | } | ||
283 | |||
284 | func (d *dnsResolver) lookupTXT() string { | ||
285 | ss, err := d.resolver.LookupTXT(d.ctx, d.host) | ||
286 | if err != nil { | ||
287 | grpclog.Infof("grpc: failed dns TXT record lookup due to %v.\n", err) | ||
288 | return "" | ||
289 | } | ||
290 | var res string | ||
291 | for _, s := range ss { | ||
292 | res += s | ||
293 | } | ||
294 | |||
295 | // TXT record must have "grpc_config=" attribute in order to be used as service config. | ||
296 | if !strings.HasPrefix(res, txtAttribute) { | ||
297 | grpclog.Warningf("grpc: TXT record %v missing %v attribute", res, txtAttribute) | ||
298 | return "" | ||
299 | } | ||
300 | return strings.TrimPrefix(res, txtAttribute) | ||
301 | } | ||
302 | |||
303 | func (d *dnsResolver) lookupHost() []resolver.Address { | ||
304 | var newAddrs []resolver.Address | ||
305 | addrs, err := d.resolver.LookupHost(d.ctx, d.host) | ||
306 | if err != nil { | ||
307 | grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err) | ||
308 | return nil | ||
309 | } | ||
310 | for _, a := range addrs { | ||
311 | a, ok := formatIP(a) | ||
312 | if !ok { | ||
313 | grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err) | ||
314 | continue | ||
315 | } | ||
316 | addr := a + ":" + d.port | ||
317 | newAddrs = append(newAddrs, resolver.Address{Addr: addr}) | ||
318 | } | ||
319 | return newAddrs | ||
320 | } | ||
321 | |||
322 | func (d *dnsResolver) lookup() ([]resolver.Address, string) { | ||
323 | newAddrs := d.lookupSRV() | ||
324 | // Support fallback to non-balancer address. | ||
325 | newAddrs = append(newAddrs, d.lookupHost()...) | ||
326 | if d.disableServiceConfig { | ||
327 | return newAddrs, "" | ||
328 | } | ||
329 | sc := d.lookupTXT() | ||
330 | return newAddrs, canaryingSC(sc) | ||
331 | } | ||
332 | |||
333 | // formatIP returns ok = false if addr is not a valid textual representation of an IP address. | ||
334 | // If addr is an IPv4 address, return the addr and ok = true. | ||
335 | // If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true. | ||
336 | func formatIP(addr string) (addrIP string, ok bool) { | ||
337 | ip := net.ParseIP(addr) | ||
338 | if ip == nil { | ||
339 | return "", false | ||
340 | } | ||
341 | if ip.To4() != nil { | ||
342 | return addr, true | ||
343 | } | ||
344 | return "[" + addr + "]", true | ||
345 | } | ||
346 | |||
347 | // parseTarget takes the user input target string and default port, returns formatted host and port info. | ||
348 | // If target doesn't specify a port, set the port to be the defaultPort. | ||
349 | // If target is in IPv6 format and host-name is enclosed in sqarue brackets, brackets | ||
350 | // are strippd when setting the host. | ||
351 | // examples: | ||
352 | // target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443" | ||
353 | // target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80" | ||
354 | // target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443" | ||
355 | // target: ":80" defaultPort: "443" returns host: "localhost", port: "80" | ||
356 | func parseTarget(target, defaultPort string) (host, port string, err error) { | ||
357 | if target == "" { | ||
358 | return "", "", errMissingAddr | ||
359 | } | ||
360 | if ip := net.ParseIP(target); ip != nil { | ||
361 | // target is an IPv4 or IPv6(without brackets) address | ||
362 | return target, defaultPort, nil | ||
363 | } | ||
364 | if host, port, err = net.SplitHostPort(target); err == nil { | ||
365 | if port == "" { | ||
366 | // If the port field is empty (target ends with colon), e.g. "[::1]:", this is an error. | ||
367 | return "", "", errEndsWithColon | ||
368 | } | ||
369 | // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port | ||
370 | if host == "" { | ||
371 | // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed. | ||
372 | host = "localhost" | ||
373 | } | ||
374 | return host, port, nil | ||
375 | } | ||
376 | if host, port, err = net.SplitHostPort(target + ":" + defaultPort); err == nil { | ||
377 | // target doesn't have port | ||
378 | return host, port, nil | ||
379 | } | ||
380 | return "", "", fmt.Errorf("invalid target address %v, error info: %v", target, err) | ||
381 | } | ||
382 | |||
383 | type rawChoice struct { | ||
384 | ClientLanguage *[]string `json:"clientLanguage,omitempty"` | ||
385 | Percentage *int `json:"percentage,omitempty"` | ||
386 | ClientHostName *[]string `json:"clientHostName,omitempty"` | ||
387 | ServiceConfig *json.RawMessage `json:"serviceConfig,omitempty"` | ||
388 | } | ||
389 | |||
390 | func containsString(a *[]string, b string) bool { | ||
391 | if a == nil { | ||
392 | return true | ||
393 | } | ||
394 | for _, c := range *a { | ||
395 | if c == b { | ||
396 | return true | ||
397 | } | ||
398 | } | ||
399 | return false | ||
400 | } | ||
401 | |||
402 | func chosenByPercentage(a *int) bool { | ||
403 | if a == nil { | ||
404 | return true | ||
405 | } | ||
406 | return grpcrand.Intn(100)+1 <= *a | ||
407 | } | ||
408 | |||
409 | func canaryingSC(js string) string { | ||
410 | if js == "" { | ||
411 | return "" | ||
412 | } | ||
413 | var rcs []rawChoice | ||
414 | err := json.Unmarshal([]byte(js), &rcs) | ||
415 | if err != nil { | ||
416 | grpclog.Warningf("grpc: failed to parse service config json string due to %v.\n", err) | ||
417 | return "" | ||
418 | } | ||
419 | cliHostname, err := os.Hostname() | ||
420 | if err != nil { | ||
421 | grpclog.Warningf("grpc: failed to get client hostname due to %v.\n", err) | ||
422 | return "" | ||
423 | } | ||
424 | var sc string | ||
425 | for _, c := range rcs { | ||
426 | if !containsString(c.ClientLanguage, golang) || | ||
427 | !chosenByPercentage(c.Percentage) || | ||
428 | !containsString(c.ClientHostName, cliHostname) || | ||
429 | c.ServiceConfig == nil { | ||
430 | continue | ||
431 | } | ||
432 | sc = string(*c.ServiceConfig) | ||
433 | break | ||
434 | } | ||
435 | return sc | ||
436 | } | ||
diff --git a/vendor/google.golang.org/grpc/resolver/passthrough/passthrough.go b/vendor/google.golang.org/grpc/resolver/passthrough/passthrough.go new file mode 100644 index 0000000..b76010d --- /dev/null +++ b/vendor/google.golang.org/grpc/resolver/passthrough/passthrough.go | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package passthrough implements a pass-through resolver. It sends the target | ||
20 | // name without scheme back to gRPC as resolved address. | ||
21 | package passthrough | ||
22 | |||
23 | import "google.golang.org/grpc/resolver" | ||
24 | |||
25 | const scheme = "passthrough" | ||
26 | |||
27 | type passthroughBuilder struct{} | ||
28 | |||
29 | func (*passthroughBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) { | ||
30 | r := &passthroughResolver{ | ||
31 | target: target, | ||
32 | cc: cc, | ||
33 | } | ||
34 | r.start() | ||
35 | return r, nil | ||
36 | } | ||
37 | |||
38 | func (*passthroughBuilder) Scheme() string { | ||
39 | return scheme | ||
40 | } | ||
41 | |||
42 | type passthroughResolver struct { | ||
43 | target resolver.Target | ||
44 | cc resolver.ClientConn | ||
45 | } | ||
46 | |||
47 | func (r *passthroughResolver) start() { | ||
48 | r.cc.NewAddress([]resolver.Address{{Addr: r.target.Endpoint}}) | ||
49 | } | ||
50 | |||
51 | func (*passthroughResolver) ResolveNow(o resolver.ResolveNowOption) {} | ||
52 | |||
53 | func (*passthroughResolver) Close() {} | ||
54 | |||
55 | func init() { | ||
56 | resolver.Register(&passthroughBuilder{}) | ||
57 | } | ||
diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go new file mode 100644 index 0000000..145cf47 --- /dev/null +++ b/vendor/google.golang.org/grpc/resolver/resolver.go | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package resolver defines APIs for name resolution in gRPC. | ||
20 | // All APIs in this package are experimental. | ||
21 | package resolver | ||
22 | |||
23 | var ( | ||
24 | // m is a map from scheme to resolver builder. | ||
25 | m = make(map[string]Builder) | ||
26 | // defaultScheme is the default scheme to use. | ||
27 | defaultScheme = "passthrough" | ||
28 | ) | ||
29 | |||
30 | // TODO(bar) install dns resolver in init(){}. | ||
31 | |||
32 | // Register registers the resolver builder to the resolver map. b.Scheme will be | ||
33 | // used as the scheme registered with this builder. | ||
34 | // | ||
35 | // NOTE: this function must only be called during initialization time (i.e. in | ||
36 | // an init() function), and is not thread-safe. If multiple Resolvers are | ||
37 | // registered with the same name, the one registered last will take effect. | ||
38 | func Register(b Builder) { | ||
39 | m[b.Scheme()] = b | ||
40 | } | ||
41 | |||
42 | // Get returns the resolver builder registered with the given scheme. | ||
43 | // | ||
44 | // If no builder is register with the scheme, nil will be returned. | ||
45 | func Get(scheme string) Builder { | ||
46 | if b, ok := m[scheme]; ok { | ||
47 | return b | ||
48 | } | ||
49 | return nil | ||
50 | } | ||
51 | |||
52 | // SetDefaultScheme sets the default scheme that will be used. The default | ||
53 | // default scheme is "passthrough". | ||
54 | // | ||
55 | // NOTE: this function must only be called during initialization time (i.e. in | ||
56 | // an init() function), and is not thread-safe. The scheme set last overrides | ||
57 | // previously set values. | ||
58 | func SetDefaultScheme(scheme string) { | ||
59 | defaultScheme = scheme | ||
60 | } | ||
61 | |||
62 | // GetDefaultScheme gets the default scheme that will be used. | ||
63 | func GetDefaultScheme() string { | ||
64 | return defaultScheme | ||
65 | } | ||
66 | |||
67 | // AddressType indicates the address type returned by name resolution. | ||
68 | type AddressType uint8 | ||
69 | |||
70 | const ( | ||
71 | // Backend indicates the address is for a backend server. | ||
72 | Backend AddressType = iota | ||
73 | // GRPCLB indicates the address is for a grpclb load balancer. | ||
74 | GRPCLB | ||
75 | ) | ||
76 | |||
77 | // Address represents a server the client connects to. | ||
78 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | ||
79 | type Address struct { | ||
80 | // Addr is the server address on which a connection will be established. | ||
81 | Addr string | ||
82 | // Type is the type of this address. | ||
83 | Type AddressType | ||
84 | // ServerName is the name of this address. | ||
85 | // | ||
86 | // e.g. if Type is GRPCLB, ServerName should be the name of the remote load | ||
87 | // balancer, not the name of the backend. | ||
88 | ServerName string | ||
89 | // Metadata is the information associated with Addr, which may be used | ||
90 | // to make load balancing decision. | ||
91 | Metadata interface{} | ||
92 | } | ||
93 | |||
94 | // BuildOption includes additional information for the builder to create | ||
95 | // the resolver. | ||
96 | type BuildOption struct { | ||
97 | // DisableServiceConfig indicates whether resolver should fetch service config data. | ||
98 | DisableServiceConfig bool | ||
99 | } | ||
100 | |||
101 | // ClientConn contains the callbacks for resolver to notify any updates | ||
102 | // to the gRPC ClientConn. | ||
103 | // | ||
104 | // This interface is to be implemented by gRPC. Users should not need a | ||
105 | // brand new implementation of this interface. For the situations like | ||
106 | // testing, the new implementation should embed this interface. This allows | ||
107 | // gRPC to add new methods to this interface. | ||
108 | type ClientConn interface { | ||
109 | // NewAddress is called by resolver to notify ClientConn a new list | ||
110 | // of resolved addresses. | ||
111 | // The address list should be the complete list of resolved addresses. | ||
112 | NewAddress(addresses []Address) | ||
113 | // NewServiceConfig is called by resolver to notify ClientConn a new | ||
114 | // service config. The service config should be provided as a json string. | ||
115 | NewServiceConfig(serviceConfig string) | ||
116 | } | ||
117 | |||
118 | // Target represents a target for gRPC, as specified in: | ||
119 | // https://github.com/grpc/grpc/blob/master/doc/naming.md. | ||
120 | type Target struct { | ||
121 | Scheme string | ||
122 | Authority string | ||
123 | Endpoint string | ||
124 | } | ||
125 | |||
126 | // Builder creates a resolver that will be used to watch name resolution updates. | ||
127 | type Builder interface { | ||
128 | // Build creates a new resolver for the given target. | ||
129 | // | ||
130 | // gRPC dial calls Build synchronously, and fails if the returned error is | ||
131 | // not nil. | ||
132 | Build(target Target, cc ClientConn, opts BuildOption) (Resolver, error) | ||
133 | // Scheme returns the scheme supported by this resolver. | ||
134 | // Scheme is defined at https://github.com/grpc/grpc/blob/master/doc/naming.md. | ||
135 | Scheme() string | ||
136 | } | ||
137 | |||
138 | // ResolveNowOption includes additional information for ResolveNow. | ||
139 | type ResolveNowOption struct{} | ||
140 | |||
141 | // Resolver watches for the updates on the specified target. | ||
142 | // Updates include address updates and service config updates. | ||
143 | type Resolver interface { | ||
144 | // ResolveNow will be called by gRPC to try to resolve the target name | ||
145 | // again. It's just a hint, resolver can ignore this if it's not necessary. | ||
146 | // | ||
147 | // It could be called multiple times concurrently. | ||
148 | ResolveNow(ResolveNowOption) | ||
149 | // Close closes the resolver. | ||
150 | Close() | ||
151 | } | ||
152 | |||
153 | // UnregisterForTesting removes the resolver builder with the given scheme from the | ||
154 | // resolver map. | ||
155 | // This function is for testing only. | ||
156 | func UnregisterForTesting(scheme string) { | ||
157 | delete(m, scheme) | ||
158 | } | ||
diff --git a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go new file mode 100644 index 0000000..50991ea --- /dev/null +++ b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "fmt" | ||
23 | "strings" | ||
24 | |||
25 | "google.golang.org/grpc/grpclog" | ||
26 | "google.golang.org/grpc/internal/channelz" | ||
27 | "google.golang.org/grpc/resolver" | ||
28 | ) | ||
29 | |||
30 | // ccResolverWrapper is a wrapper on top of cc for resolvers. | ||
31 | // It implements resolver.ClientConnection interface. | ||
32 | type ccResolverWrapper struct { | ||
33 | cc *ClientConn | ||
34 | resolver resolver.Resolver | ||
35 | addrCh chan []resolver.Address | ||
36 | scCh chan string | ||
37 | done chan struct{} | ||
38 | lastAddressesCount int | ||
39 | } | ||
40 | |||
41 | // split2 returns the values from strings.SplitN(s, sep, 2). | ||
42 | // If sep is not found, it returns ("", "", false) instead. | ||
43 | func split2(s, sep string) (string, string, bool) { | ||
44 | spl := strings.SplitN(s, sep, 2) | ||
45 | if len(spl) < 2 { | ||
46 | return "", "", false | ||
47 | } | ||
48 | return spl[0], spl[1], true | ||
49 | } | ||
50 | |||
51 | // parseTarget splits target into a struct containing scheme, authority and | ||
52 | // endpoint. | ||
53 | // | ||
54 | // If target is not a valid scheme://authority/endpoint, it returns {Endpoint: | ||
55 | // target}. | ||
56 | func parseTarget(target string) (ret resolver.Target) { | ||
57 | var ok bool | ||
58 | ret.Scheme, ret.Endpoint, ok = split2(target, "://") | ||
59 | if !ok { | ||
60 | return resolver.Target{Endpoint: target} | ||
61 | } | ||
62 | ret.Authority, ret.Endpoint, ok = split2(ret.Endpoint, "/") | ||
63 | if !ok { | ||
64 | return resolver.Target{Endpoint: target} | ||
65 | } | ||
66 | return ret | ||
67 | } | ||
68 | |||
69 | // newCCResolverWrapper parses cc.target for scheme and gets the resolver | ||
70 | // builder for this scheme and builds the resolver. The monitoring goroutine | ||
71 | // for it is not started yet and can be created by calling start(). | ||
72 | // | ||
73 | // If withResolverBuilder dial option is set, the specified resolver will be | ||
74 | // used instead. | ||
75 | func newCCResolverWrapper(cc *ClientConn) (*ccResolverWrapper, error) { | ||
76 | rb := cc.dopts.resolverBuilder | ||
77 | if rb == nil { | ||
78 | return nil, fmt.Errorf("could not get resolver for scheme: %q", cc.parsedTarget.Scheme) | ||
79 | } | ||
80 | |||
81 | ccr := &ccResolverWrapper{ | ||
82 | cc: cc, | ||
83 | addrCh: make(chan []resolver.Address, 1), | ||
84 | scCh: make(chan string, 1), | ||
85 | done: make(chan struct{}), | ||
86 | } | ||
87 | |||
88 | var err error | ||
89 | ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, resolver.BuildOption{DisableServiceConfig: cc.dopts.disableServiceConfig}) | ||
90 | if err != nil { | ||
91 | return nil, err | ||
92 | } | ||
93 | return ccr, nil | ||
94 | } | ||
95 | |||
96 | func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOption) { | ||
97 | ccr.resolver.ResolveNow(o) | ||
98 | } | ||
99 | |||
100 | func (ccr *ccResolverWrapper) close() { | ||
101 | ccr.resolver.Close() | ||
102 | close(ccr.done) | ||
103 | } | ||
104 | |||
105 | // NewAddress is called by the resolver implemenetion to send addresses to gRPC. | ||
106 | func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) { | ||
107 | select { | ||
108 | case <-ccr.done: | ||
109 | return | ||
110 | default: | ||
111 | } | ||
112 | grpclog.Infof("ccResolverWrapper: sending new addresses to cc: %v", addrs) | ||
113 | if channelz.IsOn() { | ||
114 | ccr.addChannelzTraceEvent(addrs) | ||
115 | } | ||
116 | ccr.cc.handleResolvedAddrs(addrs, nil) | ||
117 | } | ||
118 | |||
119 | // NewServiceConfig is called by the resolver implemenetion to send service | ||
120 | // configs to gRPC. | ||
121 | func (ccr *ccResolverWrapper) NewServiceConfig(sc string) { | ||
122 | select { | ||
123 | case <-ccr.done: | ||
124 | return | ||
125 | default: | ||
126 | } | ||
127 | grpclog.Infof("ccResolverWrapper: got new service config: %v", sc) | ||
128 | ccr.cc.handleServiceConfig(sc) | ||
129 | } | ||
130 | |||
131 | func (ccr *ccResolverWrapper) addChannelzTraceEvent(addrs []resolver.Address) { | ||
132 | if len(addrs) == 0 && ccr.lastAddressesCount != 0 { | ||
133 | channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{ | ||
134 | Desc: "Resolver returns an empty address list", | ||
135 | Severity: channelz.CtWarning, | ||
136 | }) | ||
137 | } else if len(addrs) != 0 && ccr.lastAddressesCount == 0 { | ||
138 | var s string | ||
139 | for i, a := range addrs { | ||
140 | if a.ServerName != "" { | ||
141 | s += a.Addr + "(" + a.ServerName + ")" | ||
142 | } else { | ||
143 | s += a.Addr | ||
144 | } | ||
145 | if i != len(addrs)-1 { | ||
146 | s += " " | ||
147 | } | ||
148 | } | ||
149 | channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{ | ||
150 | Desc: fmt.Sprintf("Resolver returns a non-empty address list (previous one was empty) %q", s), | ||
151 | Severity: channelz.CtINFO, | ||
152 | }) | ||
153 | } | ||
154 | ccr.lastAddressesCount = len(addrs) | ||
155 | } | ||
diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index 9b9d388..8d0d3dc 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go | |||
@@ -21,24 +21,31 @@ package grpc | |||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "bytes" |
23 | "compress/gzip" | 23 | "compress/gzip" |
24 | "context" | ||
24 | "encoding/binary" | 25 | "encoding/binary" |
26 | "fmt" | ||
25 | "io" | 27 | "io" |
26 | "io/ioutil" | 28 | "io/ioutil" |
27 | "math" | 29 | "math" |
30 | "net/url" | ||
31 | "strings" | ||
28 | "sync" | 32 | "sync" |
29 | "time" | 33 | "time" |
30 | 34 | ||
31 | "golang.org/x/net/context" | ||
32 | "google.golang.org/grpc/codes" | 35 | "google.golang.org/grpc/codes" |
33 | "google.golang.org/grpc/credentials" | 36 | "google.golang.org/grpc/credentials" |
37 | "google.golang.org/grpc/encoding" | ||
38 | "google.golang.org/grpc/encoding/proto" | ||
39 | "google.golang.org/grpc/internal/transport" | ||
34 | "google.golang.org/grpc/metadata" | 40 | "google.golang.org/grpc/metadata" |
35 | "google.golang.org/grpc/peer" | 41 | "google.golang.org/grpc/peer" |
36 | "google.golang.org/grpc/stats" | 42 | "google.golang.org/grpc/stats" |
37 | "google.golang.org/grpc/status" | 43 | "google.golang.org/grpc/status" |
38 | "google.golang.org/grpc/transport" | ||
39 | ) | 44 | ) |
40 | 45 | ||
41 | // Compressor defines the interface gRPC uses to compress a message. | 46 | // Compressor defines the interface gRPC uses to compress a message. |
47 | // | ||
48 | // Deprecated: use package encoding. | ||
42 | type Compressor interface { | 49 | type Compressor interface { |
43 | // Do compresses p into w. | 50 | // Do compresses p into w. |
44 | Do(w io.Writer, p []byte) error | 51 | Do(w io.Writer, p []byte) error |
@@ -51,18 +58,39 @@ type gzipCompressor struct { | |||
51 | } | 58 | } |
52 | 59 | ||
53 | // NewGZIPCompressor creates a Compressor based on GZIP. | 60 | // NewGZIPCompressor creates a Compressor based on GZIP. |
61 | // | ||
62 | // Deprecated: use package encoding/gzip. | ||
54 | func NewGZIPCompressor() Compressor { | 63 | func NewGZIPCompressor() Compressor { |
64 | c, _ := NewGZIPCompressorWithLevel(gzip.DefaultCompression) | ||
65 | return c | ||
66 | } | ||
67 | |||
68 | // NewGZIPCompressorWithLevel is like NewGZIPCompressor but specifies the gzip compression level instead | ||
69 | // of assuming DefaultCompression. | ||
70 | // | ||
71 | // The error returned will be nil if the level is valid. | ||
72 | // | ||
73 | // Deprecated: use package encoding/gzip. | ||
74 | func NewGZIPCompressorWithLevel(level int) (Compressor, error) { | ||
75 | if level < gzip.DefaultCompression || level > gzip.BestCompression { | ||
76 | return nil, fmt.Errorf("grpc: invalid compression level: %d", level) | ||
77 | } | ||
55 | return &gzipCompressor{ | 78 | return &gzipCompressor{ |
56 | pool: sync.Pool{ | 79 | pool: sync.Pool{ |
57 | New: func() interface{} { | 80 | New: func() interface{} { |
58 | return gzip.NewWriter(ioutil.Discard) | 81 | w, err := gzip.NewWriterLevel(ioutil.Discard, level) |
82 | if err != nil { | ||
83 | panic(err) | ||
84 | } | ||
85 | return w | ||
59 | }, | 86 | }, |
60 | }, | 87 | }, |
61 | } | 88 | }, nil |
62 | } | 89 | } |
63 | 90 | ||
64 | func (c *gzipCompressor) Do(w io.Writer, p []byte) error { | 91 | func (c *gzipCompressor) Do(w io.Writer, p []byte) error { |
65 | z := c.pool.Get().(*gzip.Writer) | 92 | z := c.pool.Get().(*gzip.Writer) |
93 | defer c.pool.Put(z) | ||
66 | z.Reset(w) | 94 | z.Reset(w) |
67 | if _, err := z.Write(p); err != nil { | 95 | if _, err := z.Write(p); err != nil { |
68 | return err | 96 | return err |
@@ -75,6 +103,8 @@ func (c *gzipCompressor) Type() string { | |||
75 | } | 103 | } |
76 | 104 | ||
77 | // Decompressor defines the interface gRPC uses to decompress a message. | 105 | // Decompressor defines the interface gRPC uses to decompress a message. |
106 | // | ||
107 | // Deprecated: use package encoding. | ||
78 | type Decompressor interface { | 108 | type Decompressor interface { |
79 | // Do reads the data from r and uncompress them. | 109 | // Do reads the data from r and uncompress them. |
80 | Do(r io.Reader) ([]byte, error) | 110 | Do(r io.Reader) ([]byte, error) |
@@ -87,6 +117,8 @@ type gzipDecompressor struct { | |||
87 | } | 117 | } |
88 | 118 | ||
89 | // NewGZIPDecompressor creates a Decompressor based on GZIP. | 119 | // NewGZIPDecompressor creates a Decompressor based on GZIP. |
120 | // | ||
121 | // Deprecated: use package encoding/gzip. | ||
90 | func NewGZIPDecompressor() Decompressor { | 122 | func NewGZIPDecompressor() Decompressor { |
91 | return &gzipDecompressor{} | 123 | return &gzipDecompressor{} |
92 | } | 124 | } |
@@ -121,17 +153,23 @@ func (d *gzipDecompressor) Type() string { | |||
121 | 153 | ||
122 | // callInfo contains all related configuration and information about an RPC. | 154 | // callInfo contains all related configuration and information about an RPC. |
123 | type callInfo struct { | 155 | type callInfo struct { |
156 | compressorType string | ||
124 | failFast bool | 157 | failFast bool |
125 | headerMD metadata.MD | 158 | stream ClientStream |
126 | trailerMD metadata.MD | ||
127 | peer *peer.Peer | ||
128 | traceInfo traceInfo // in trace.go | ||
129 | maxReceiveMessageSize *int | 159 | maxReceiveMessageSize *int |
130 | maxSendMessageSize *int | 160 | maxSendMessageSize *int |
131 | creds credentials.PerRPCCredentials | 161 | creds credentials.PerRPCCredentials |
162 | contentSubtype string | ||
163 | codec baseCodec | ||
164 | maxRetryRPCBufferSize int | ||
132 | } | 165 | } |
133 | 166 | ||
134 | var defaultCallInfo = callInfo{failFast: true} | 167 | func defaultCallInfo() *callInfo { |
168 | return &callInfo{ | ||
169 | failFast: true, | ||
170 | maxRetryRPCBufferSize: 256 * 1024, // 256KB | ||
171 | } | ||
172 | } | ||
135 | 173 | ||
136 | // CallOption configures a Call before it starts or extracts information from | 174 | // CallOption configures a Call before it starts or extracts information from |
137 | // a Call after it completes. | 175 | // a Call after it completes. |
@@ -153,87 +191,267 @@ type EmptyCallOption struct{} | |||
153 | func (EmptyCallOption) before(*callInfo) error { return nil } | 191 | func (EmptyCallOption) before(*callInfo) error { return nil } |
154 | func (EmptyCallOption) after(*callInfo) {} | 192 | func (EmptyCallOption) after(*callInfo) {} |
155 | 193 | ||
156 | type beforeCall func(c *callInfo) error | ||
157 | |||
158 | func (o beforeCall) before(c *callInfo) error { return o(c) } | ||
159 | func (o beforeCall) after(c *callInfo) {} | ||
160 | |||
161 | type afterCall func(c *callInfo) | ||
162 | |||
163 | func (o afterCall) before(c *callInfo) error { return nil } | ||
164 | func (o afterCall) after(c *callInfo) { o(c) } | ||
165 | |||
166 | // Header returns a CallOptions that retrieves the header metadata | 194 | // Header returns a CallOptions that retrieves the header metadata |
167 | // for a unary RPC. | 195 | // for a unary RPC. |
168 | func Header(md *metadata.MD) CallOption { | 196 | func Header(md *metadata.MD) CallOption { |
169 | return afterCall(func(c *callInfo) { | 197 | return HeaderCallOption{HeaderAddr: md} |
170 | *md = c.headerMD | 198 | } |
171 | }) | 199 | |
200 | // HeaderCallOption is a CallOption for collecting response header metadata. | ||
201 | // The metadata field will be populated *after* the RPC completes. | ||
202 | // This is an EXPERIMENTAL API. | ||
203 | type HeaderCallOption struct { | ||
204 | HeaderAddr *metadata.MD | ||
205 | } | ||
206 | |||
207 | func (o HeaderCallOption) before(c *callInfo) error { return nil } | ||
208 | func (o HeaderCallOption) after(c *callInfo) { | ||
209 | if c.stream != nil { | ||
210 | *o.HeaderAddr, _ = c.stream.Header() | ||
211 | } | ||
172 | } | 212 | } |
173 | 213 | ||
174 | // Trailer returns a CallOptions that retrieves the trailer metadata | 214 | // Trailer returns a CallOptions that retrieves the trailer metadata |
175 | // for a unary RPC. | 215 | // for a unary RPC. |
176 | func Trailer(md *metadata.MD) CallOption { | 216 | func Trailer(md *metadata.MD) CallOption { |
177 | return afterCall(func(c *callInfo) { | 217 | return TrailerCallOption{TrailerAddr: md} |
178 | *md = c.trailerMD | 218 | } |
179 | }) | 219 | |
220 | // TrailerCallOption is a CallOption for collecting response trailer metadata. | ||
221 | // The metadata field will be populated *after* the RPC completes. | ||
222 | // This is an EXPERIMENTAL API. | ||
223 | type TrailerCallOption struct { | ||
224 | TrailerAddr *metadata.MD | ||
225 | } | ||
226 | |||
227 | func (o TrailerCallOption) before(c *callInfo) error { return nil } | ||
228 | func (o TrailerCallOption) after(c *callInfo) { | ||
229 | if c.stream != nil { | ||
230 | *o.TrailerAddr = c.stream.Trailer() | ||
231 | } | ||
232 | } | ||
233 | |||
234 | // Peer returns a CallOption that retrieves peer information for a unary RPC. | ||
235 | // The peer field will be populated *after* the RPC completes. | ||
236 | func Peer(p *peer.Peer) CallOption { | ||
237 | return PeerCallOption{PeerAddr: p} | ||
180 | } | 238 | } |
181 | 239 | ||
182 | // Peer returns a CallOption that retrieves peer information for a | 240 | // PeerCallOption is a CallOption for collecting the identity of the remote |
183 | // unary RPC. | 241 | // peer. The peer field will be populated *after* the RPC completes. |
184 | func Peer(peer *peer.Peer) CallOption { | 242 | // This is an EXPERIMENTAL API. |
185 | return afterCall(func(c *callInfo) { | 243 | type PeerCallOption struct { |
186 | if c.peer != nil { | 244 | PeerAddr *peer.Peer |
187 | *peer = *c.peer | 245 | } |
246 | |||
247 | func (o PeerCallOption) before(c *callInfo) error { return nil } | ||
248 | func (o PeerCallOption) after(c *callInfo) { | ||
249 | if c.stream != nil { | ||
250 | if x, ok := peer.FromContext(c.stream.Context()); ok { | ||
251 | *o.PeerAddr = *x | ||
188 | } | 252 | } |
189 | }) | 253 | } |
190 | } | 254 | } |
191 | 255 | ||
192 | // FailFast configures the action to take when an RPC is attempted on broken | 256 | // WaitForReady configures the action to take when an RPC is attempted on broken |
193 | // connections or unreachable servers. If failfast is true, the RPC will fail | 257 | // connections or unreachable servers. If waitForReady is false, the RPC will fail |
194 | // immediately. Otherwise, the RPC client will block the call until a | 258 | // immediately. Otherwise, the RPC client will block the call until a |
195 | // connection is available (or the call is canceled or times out) and will retry | 259 | // connection is available (or the call is canceled or times out) and will |
196 | // the call if it fails due to a transient error. Please refer to | 260 | // retry the call if it fails due to a transient error. gRPC will not retry if |
261 | // data was written to the wire unless the server indicates it did not process | ||
262 | // the data. Please refer to | ||
197 | // https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md. | 263 | // https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md. |
198 | // Note: failFast is default to true. | 264 | // |
265 | // By default, RPCs don't "wait for ready". | ||
266 | func WaitForReady(waitForReady bool) CallOption { | ||
267 | return FailFastCallOption{FailFast: !waitForReady} | ||
268 | } | ||
269 | |||
270 | // FailFast is the opposite of WaitForReady. | ||
271 | // | ||
272 | // Deprecated: use WaitForReady. | ||
199 | func FailFast(failFast bool) CallOption { | 273 | func FailFast(failFast bool) CallOption { |
200 | return beforeCall(func(c *callInfo) error { | 274 | return FailFastCallOption{FailFast: failFast} |
201 | c.failFast = failFast | ||
202 | return nil | ||
203 | }) | ||
204 | } | 275 | } |
205 | 276 | ||
277 | // FailFastCallOption is a CallOption for indicating whether an RPC should fail | ||
278 | // fast or not. | ||
279 | // This is an EXPERIMENTAL API. | ||
280 | type FailFastCallOption struct { | ||
281 | FailFast bool | ||
282 | } | ||
283 | |||
284 | func (o FailFastCallOption) before(c *callInfo) error { | ||
285 | c.failFast = o.FailFast | ||
286 | return nil | ||
287 | } | ||
288 | func (o FailFastCallOption) after(c *callInfo) {} | ||
289 | |||
206 | // MaxCallRecvMsgSize returns a CallOption which sets the maximum message size the client can receive. | 290 | // MaxCallRecvMsgSize returns a CallOption which sets the maximum message size the client can receive. |
207 | func MaxCallRecvMsgSize(s int) CallOption { | 291 | func MaxCallRecvMsgSize(s int) CallOption { |
208 | return beforeCall(func(o *callInfo) error { | 292 | return MaxRecvMsgSizeCallOption{MaxRecvMsgSize: s} |
209 | o.maxReceiveMessageSize = &s | 293 | } |
210 | return nil | 294 | |
211 | }) | 295 | // MaxRecvMsgSizeCallOption is a CallOption that indicates the maximum message |
296 | // size the client can receive. | ||
297 | // This is an EXPERIMENTAL API. | ||
298 | type MaxRecvMsgSizeCallOption struct { | ||
299 | MaxRecvMsgSize int | ||
212 | } | 300 | } |
213 | 301 | ||
302 | func (o MaxRecvMsgSizeCallOption) before(c *callInfo) error { | ||
303 | c.maxReceiveMessageSize = &o.MaxRecvMsgSize | ||
304 | return nil | ||
305 | } | ||
306 | func (o MaxRecvMsgSizeCallOption) after(c *callInfo) {} | ||
307 | |||
214 | // MaxCallSendMsgSize returns a CallOption which sets the maximum message size the client can send. | 308 | // MaxCallSendMsgSize returns a CallOption which sets the maximum message size the client can send. |
215 | func MaxCallSendMsgSize(s int) CallOption { | 309 | func MaxCallSendMsgSize(s int) CallOption { |
216 | return beforeCall(func(o *callInfo) error { | 310 | return MaxSendMsgSizeCallOption{MaxSendMsgSize: s} |
217 | o.maxSendMessageSize = &s | 311 | } |
218 | return nil | 312 | |
219 | }) | 313 | // MaxSendMsgSizeCallOption is a CallOption that indicates the maximum message |
314 | // size the client can send. | ||
315 | // This is an EXPERIMENTAL API. | ||
316 | type MaxSendMsgSizeCallOption struct { | ||
317 | MaxSendMsgSize int | ||
220 | } | 318 | } |
221 | 319 | ||
320 | func (o MaxSendMsgSizeCallOption) before(c *callInfo) error { | ||
321 | c.maxSendMessageSize = &o.MaxSendMsgSize | ||
322 | return nil | ||
323 | } | ||
324 | func (o MaxSendMsgSizeCallOption) after(c *callInfo) {} | ||
325 | |||
222 | // PerRPCCredentials returns a CallOption that sets credentials.PerRPCCredentials | 326 | // PerRPCCredentials returns a CallOption that sets credentials.PerRPCCredentials |
223 | // for a call. | 327 | // for a call. |
224 | func PerRPCCredentials(creds credentials.PerRPCCredentials) CallOption { | 328 | func PerRPCCredentials(creds credentials.PerRPCCredentials) CallOption { |
225 | return beforeCall(func(c *callInfo) error { | 329 | return PerRPCCredsCallOption{Creds: creds} |
226 | c.creds = creds | 330 | } |
227 | return nil | 331 | |
228 | }) | 332 | // PerRPCCredsCallOption is a CallOption that indicates the per-RPC |
333 | // credentials to use for the call. | ||
334 | // This is an EXPERIMENTAL API. | ||
335 | type PerRPCCredsCallOption struct { | ||
336 | Creds credentials.PerRPCCredentials | ||
337 | } | ||
338 | |||
339 | func (o PerRPCCredsCallOption) before(c *callInfo) error { | ||
340 | c.creds = o.Creds | ||
341 | return nil | ||
342 | } | ||
343 | func (o PerRPCCredsCallOption) after(c *callInfo) {} | ||
344 | |||
345 | // UseCompressor returns a CallOption which sets the compressor used when | ||
346 | // sending the request. If WithCompressor is also set, UseCompressor has | ||
347 | // higher priority. | ||
348 | // | ||
349 | // This API is EXPERIMENTAL. | ||
350 | func UseCompressor(name string) CallOption { | ||
351 | return CompressorCallOption{CompressorType: name} | ||
352 | } | ||
353 | |||
354 | // CompressorCallOption is a CallOption that indicates the compressor to use. | ||
355 | // This is an EXPERIMENTAL API. | ||
356 | type CompressorCallOption struct { | ||
357 | CompressorType string | ||
358 | } | ||
359 | |||
360 | func (o CompressorCallOption) before(c *callInfo) error { | ||
361 | c.compressorType = o.CompressorType | ||
362 | return nil | ||
363 | } | ||
364 | func (o CompressorCallOption) after(c *callInfo) {} | ||
365 | |||
366 | // CallContentSubtype returns a CallOption that will set the content-subtype | ||
367 | // for a call. For example, if content-subtype is "json", the Content-Type over | ||
368 | // the wire will be "application/grpc+json". The content-subtype is converted | ||
369 | // to lowercase before being included in Content-Type. See Content-Type on | ||
370 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for | ||
371 | // more details. | ||
372 | // | ||
373 | // If CallCustomCodec is not also used, the content-subtype will be used to | ||
374 | // look up the Codec to use in the registry controlled by RegisterCodec. See | ||
375 | // the documentation on RegisterCodec for details on registration. The lookup | ||
376 | // of content-subtype is case-insensitive. If no such Codec is found, the call | ||
377 | // will result in an error with code codes.Internal. | ||
378 | // | ||
379 | // If CallCustomCodec is also used, that Codec will be used for all request and | ||
380 | // response messages, with the content-subtype set to the given contentSubtype | ||
381 | // here for requests. | ||
382 | func CallContentSubtype(contentSubtype string) CallOption { | ||
383 | return ContentSubtypeCallOption{ContentSubtype: strings.ToLower(contentSubtype)} | ||
384 | } | ||
385 | |||
386 | // ContentSubtypeCallOption is a CallOption that indicates the content-subtype | ||
387 | // used for marshaling messages. | ||
388 | // This is an EXPERIMENTAL API. | ||
389 | type ContentSubtypeCallOption struct { | ||
390 | ContentSubtype string | ||
391 | } | ||
392 | |||
393 | func (o ContentSubtypeCallOption) before(c *callInfo) error { | ||
394 | c.contentSubtype = o.ContentSubtype | ||
395 | return nil | ||
396 | } | ||
397 | func (o ContentSubtypeCallOption) after(c *callInfo) {} | ||
398 | |||
399 | // CallCustomCodec returns a CallOption that will set the given Codec to be | ||
400 | // used for all request and response messages for a call. The result of calling | ||
401 | // String() will be used as the content-subtype in a case-insensitive manner. | ||
402 | // | ||
403 | // See Content-Type on | ||
404 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for | ||
405 | // more details. Also see the documentation on RegisterCodec and | ||
406 | // CallContentSubtype for more details on the interaction between Codec and | ||
407 | // content-subtype. | ||
408 | // | ||
409 | // This function is provided for advanced users; prefer to use only | ||
410 | // CallContentSubtype to select a registered codec instead. | ||
411 | func CallCustomCodec(codec Codec) CallOption { | ||
412 | return CustomCodecCallOption{Codec: codec} | ||
413 | } | ||
414 | |||
415 | // CustomCodecCallOption is a CallOption that indicates the codec used for | ||
416 | // marshaling messages. | ||
417 | // This is an EXPERIMENTAL API. | ||
418 | type CustomCodecCallOption struct { | ||
419 | Codec Codec | ||
420 | } | ||
421 | |||
422 | func (o CustomCodecCallOption) before(c *callInfo) error { | ||
423 | c.codec = o.Codec | ||
424 | return nil | ||
425 | } | ||
426 | func (o CustomCodecCallOption) after(c *callInfo) {} | ||
427 | |||
428 | // MaxRetryRPCBufferSize returns a CallOption that limits the amount of memory | ||
429 | // used for buffering this RPC's requests for retry purposes. | ||
430 | // | ||
431 | // This API is EXPERIMENTAL. | ||
432 | func MaxRetryRPCBufferSize(bytes int) CallOption { | ||
433 | return MaxRetryRPCBufferSizeCallOption{bytes} | ||
434 | } | ||
435 | |||
436 | // MaxRetryRPCBufferSizeCallOption is a CallOption indicating the amount of | ||
437 | // memory to be used for caching this RPC for retry purposes. | ||
438 | // This is an EXPERIMENTAL API. | ||
439 | type MaxRetryRPCBufferSizeCallOption struct { | ||
440 | MaxRetryRPCBufferSize int | ||
441 | } | ||
442 | |||
443 | func (o MaxRetryRPCBufferSizeCallOption) before(c *callInfo) error { | ||
444 | c.maxRetryRPCBufferSize = o.MaxRetryRPCBufferSize | ||
445 | return nil | ||
229 | } | 446 | } |
447 | func (o MaxRetryRPCBufferSizeCallOption) after(c *callInfo) {} | ||
230 | 448 | ||
231 | // The format of the payload: compressed or not? | 449 | // The format of the payload: compressed or not? |
232 | type payloadFormat uint8 | 450 | type payloadFormat uint8 |
233 | 451 | ||
234 | const ( | 452 | const ( |
235 | compressionNone payloadFormat = iota // no compression | 453 | compressionNone payloadFormat = 0 // no compression |
236 | compressionMade | 454 | compressionMade payloadFormat = 1 // compressed |
237 | ) | 455 | ) |
238 | 456 | ||
239 | // parser reads complete gRPC messages from the underlying reader. | 457 | // parser reads complete gRPC messages from the underlying reader. |
@@ -243,8 +461,8 @@ type parser struct { | |||
243 | // error types. | 461 | // error types. |
244 | r io.Reader | 462 | r io.Reader |
245 | 463 | ||
246 | // The header of a gRPC message. Find more detail | 464 | // The header of a gRPC message. Find more detail at |
247 | // at https://grpc.io/docs/guides/wire.html. | 465 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md |
248 | header [5]byte | 466 | header [5]byte |
249 | } | 467 | } |
250 | 468 | ||
@@ -257,7 +475,7 @@ type parser struct { | |||
257 | // * io.EOF, when no messages remain | 475 | // * io.EOF, when no messages remain |
258 | // * io.ErrUnexpectedEOF | 476 | // * io.ErrUnexpectedEOF |
259 | // * of type transport.ConnectionError | 477 | // * of type transport.ConnectionError |
260 | // * of type transport.StreamError | 478 | // * an error from the status package |
261 | // No other error values or types must be returned, which also means | 479 | // No other error values or types must be returned, which also means |
262 | // that the underlying io.Reader must not return an incompatible | 480 | // that the underlying io.Reader must not return an incompatible |
263 | // error. | 481 | // error. |
@@ -272,8 +490,11 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt | |||
272 | if length == 0 { | 490 | if length == 0 { |
273 | return pf, nil, nil | 491 | return pf, nil, nil |
274 | } | 492 | } |
275 | if length > uint32(maxReceiveMessageSize) { | 493 | if int64(length) > int64(maxInt) { |
276 | return 0, nil, Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", length, maxReceiveMessageSize) | 494 | return 0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max length allowed on current machine (%d vs. %d)", length, maxInt) |
495 | } | ||
496 | if int(length) > maxReceiveMessageSize { | ||
497 | return 0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", length, maxReceiveMessageSize) | ||
277 | } | 498 | } |
278 | // TODO(bradfitz,zhaoq): garbage. reuse buffer after proto decoding instead | 499 | // TODO(bradfitz,zhaoq): garbage. reuse buffer after proto decoding instead |
279 | // of making it for each message: | 500 | // of making it for each message: |
@@ -287,120 +508,173 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt | |||
287 | return pf, msg, nil | 508 | return pf, msg, nil |
288 | } | 509 | } |
289 | 510 | ||
290 | // encode serializes msg and prepends the message header. If msg is nil, it | 511 | // encode serializes msg and returns a buffer containing the message, or an |
291 | // generates the message header of 0 message length. | 512 | // error if it is too large to be transmitted by grpc. If msg is nil, it |
292 | func encode(c Codec, msg interface{}, cp Compressor, cbuf *bytes.Buffer, outPayload *stats.OutPayload) ([]byte, error) { | 513 | // generates an empty message. |
293 | var ( | 514 | func encode(c baseCodec, msg interface{}) ([]byte, error) { |
294 | b []byte | 515 | if msg == nil { // NOTE: typed nils will not be caught by this check |
295 | length uint | 516 | return nil, nil |
296 | ) | 517 | } |
297 | if msg != nil { | 518 | b, err := c.Marshal(msg) |
298 | var err error | 519 | if err != nil { |
299 | // TODO(zhaoq): optimize to reduce memory alloc and copying. | 520 | return nil, status.Errorf(codes.Internal, "grpc: error while marshaling: %v", err.Error()) |
300 | b, err = c.Marshal(msg) | 521 | } |
522 | if uint(len(b)) > math.MaxUint32 { | ||
523 | return nil, status.Errorf(codes.ResourceExhausted, "grpc: message too large (%d bytes)", len(b)) | ||
524 | } | ||
525 | return b, nil | ||
526 | } | ||
527 | |||
528 | // compress returns the input bytes compressed by compressor or cp. If both | ||
529 | // compressors are nil, returns nil. | ||
530 | // | ||
531 | // TODO(dfawley): eliminate cp parameter by wrapping Compressor in an encoding.Compressor. | ||
532 | func compress(in []byte, cp Compressor, compressor encoding.Compressor) ([]byte, error) { | ||
533 | if compressor == nil && cp == nil { | ||
534 | return nil, nil | ||
535 | } | ||
536 | wrapErr := func(err error) error { | ||
537 | return status.Errorf(codes.Internal, "grpc: error while compressing: %v", err.Error()) | ||
538 | } | ||
539 | cbuf := &bytes.Buffer{} | ||
540 | if compressor != nil { | ||
541 | z, err := compressor.Compress(cbuf) | ||
301 | if err != nil { | 542 | if err != nil { |
302 | return nil, Errorf(codes.Internal, "grpc: error while marshaling: %v", err.Error()) | 543 | return nil, wrapErr(err) |
303 | } | 544 | } |
304 | if outPayload != nil { | 545 | if _, err := z.Write(in); err != nil { |
305 | outPayload.Payload = msg | 546 | return nil, wrapErr(err) |
306 | // TODO truncate large payload. | ||
307 | outPayload.Data = b | ||
308 | outPayload.Length = len(b) | ||
309 | } | 547 | } |
310 | if cp != nil { | 548 | if err := z.Close(); err != nil { |
311 | if err := cp.Do(cbuf, b); err != nil { | 549 | return nil, wrapErr(err) |
312 | return nil, Errorf(codes.Internal, "grpc: error while compressing: %v", err.Error()) | 550 | } |
313 | } | 551 | } else { |
314 | b = cbuf.Bytes() | 552 | if err := cp.Do(cbuf, in); err != nil { |
553 | return nil, wrapErr(err) | ||
315 | } | 554 | } |
316 | length = uint(len(b)) | ||
317 | } | ||
318 | if length > math.MaxUint32 { | ||
319 | return nil, Errorf(codes.ResourceExhausted, "grpc: message too large (%d bytes)", length) | ||
320 | } | 555 | } |
556 | return cbuf.Bytes(), nil | ||
557 | } | ||
321 | 558 | ||
322 | const ( | 559 | const ( |
323 | payloadLen = 1 | 560 | payloadLen = 1 |
324 | sizeLen = 4 | 561 | sizeLen = 4 |
325 | ) | 562 | headerLen = payloadLen + sizeLen |
326 | 563 | ) | |
327 | var buf = make([]byte, payloadLen+sizeLen+len(b)) | ||
328 | 564 | ||
329 | // Write payload format | 565 | // msgHeader returns a 5-byte header for the message being transmitted and the |
330 | if cp == nil { | 566 | // payload, which is compData if non-nil or data otherwise. |
331 | buf[0] = byte(compressionNone) | 567 | func msgHeader(data, compData []byte) (hdr []byte, payload []byte) { |
568 | hdr = make([]byte, headerLen) | ||
569 | if compData != nil { | ||
570 | hdr[0] = byte(compressionMade) | ||
571 | data = compData | ||
332 | } else { | 572 | } else { |
333 | buf[0] = byte(compressionMade) | 573 | hdr[0] = byte(compressionNone) |
334 | } | 574 | } |
335 | // Write length of b into buf | ||
336 | binary.BigEndian.PutUint32(buf[1:], uint32(length)) | ||
337 | // Copy encoded msg to buf | ||
338 | copy(buf[5:], b) | ||
339 | 575 | ||
340 | if outPayload != nil { | 576 | // Write length of payload into buf |
341 | outPayload.WireLength = len(buf) | 577 | binary.BigEndian.PutUint32(hdr[payloadLen:], uint32(len(data))) |
342 | } | 578 | return hdr, data |
579 | } | ||
343 | 580 | ||
344 | return buf, nil | 581 | func outPayload(client bool, msg interface{}, data, payload []byte, t time.Time) *stats.OutPayload { |
582 | return &stats.OutPayload{ | ||
583 | Client: client, | ||
584 | Payload: msg, | ||
585 | Data: data, | ||
586 | Length: len(data), | ||
587 | WireLength: len(payload) + headerLen, | ||
588 | SentTime: t, | ||
589 | } | ||
345 | } | 590 | } |
346 | 591 | ||
347 | func checkRecvPayload(pf payloadFormat, recvCompress string, dc Decompressor) error { | 592 | func checkRecvPayload(pf payloadFormat, recvCompress string, haveCompressor bool) *status.Status { |
348 | switch pf { | 593 | switch pf { |
349 | case compressionNone: | 594 | case compressionNone: |
350 | case compressionMade: | 595 | case compressionMade: |
351 | if dc == nil || recvCompress != dc.Type() { | 596 | if recvCompress == "" || recvCompress == encoding.Identity { |
352 | return Errorf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", recvCompress) | 597 | return status.New(codes.Internal, "grpc: compressed flag set with identity or empty encoding") |
598 | } | ||
599 | if !haveCompressor { | ||
600 | return status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", recvCompress) | ||
353 | } | 601 | } |
354 | default: | 602 | default: |
355 | return Errorf(codes.Internal, "grpc: received unexpected payload format %d", pf) | 603 | return status.Newf(codes.Internal, "grpc: received unexpected payload format %d", pf) |
356 | } | 604 | } |
357 | return nil | 605 | return nil |
358 | } | 606 | } |
359 | 607 | ||
360 | func recv(p *parser, c Codec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, inPayload *stats.InPayload) error { | 608 | type payloadInfo struct { |
609 | wireLength int // The compressed length got from wire. | ||
610 | uncompressedBytes []byte | ||
611 | } | ||
612 | |||
613 | func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) ([]byte, error) { | ||
361 | pf, d, err := p.recvMsg(maxReceiveMessageSize) | 614 | pf, d, err := p.recvMsg(maxReceiveMessageSize) |
362 | if err != nil { | 615 | if err != nil { |
363 | return err | 616 | return nil, err |
364 | } | 617 | } |
365 | if inPayload != nil { | 618 | if payInfo != nil { |
366 | inPayload.WireLength = len(d) | 619 | payInfo.wireLength = len(d) |
367 | } | 620 | } |
368 | if err := checkRecvPayload(pf, s.RecvCompress(), dc); err != nil { | 621 | |
369 | return err | 622 | if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil { |
623 | return nil, st.Err() | ||
370 | } | 624 | } |
625 | |||
371 | if pf == compressionMade { | 626 | if pf == compressionMade { |
372 | d, err = dc.Do(bytes.NewReader(d)) | 627 | // To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor, |
373 | if err != nil { | 628 | // use this decompressor as the default. |
374 | return Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) | 629 | if dc != nil { |
630 | d, err = dc.Do(bytes.NewReader(d)) | ||
631 | if err != nil { | ||
632 | return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) | ||
633 | } | ||
634 | } else { | ||
635 | dcReader, err := compressor.Decompress(bytes.NewReader(d)) | ||
636 | if err != nil { | ||
637 | return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) | ||
638 | } | ||
639 | d, err = ioutil.ReadAll(dcReader) | ||
640 | if err != nil { | ||
641 | return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) | ||
642 | } | ||
375 | } | 643 | } |
376 | } | 644 | } |
377 | if len(d) > maxReceiveMessageSize { | 645 | if len(d) > maxReceiveMessageSize { |
378 | // TODO: Revisit the error code. Currently keep it consistent with java | 646 | // TODO: Revisit the error code. Currently keep it consistent with java |
379 | // implementation. | 647 | // implementation. |
380 | return Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize) | 648 | return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize) |
649 | } | ||
650 | return d, nil | ||
651 | } | ||
652 | |||
653 | // For the two compressor parameters, both should not be set, but if they are, | ||
654 | // dc takes precedence over compressor. | ||
655 | // TODO(dfawley): wrap the old compressor/decompressor using the new API? | ||
656 | func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) error { | ||
657 | d, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor) | ||
658 | if err != nil { | ||
659 | return err | ||
381 | } | 660 | } |
382 | if err := c.Unmarshal(d, m); err != nil { | 661 | if err := c.Unmarshal(d, m); err != nil { |
383 | return Errorf(codes.Internal, "grpc: failed to unmarshal the received message %v", err) | 662 | return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message %v", err) |
384 | } | 663 | } |
385 | if inPayload != nil { | 664 | if payInfo != nil { |
386 | inPayload.RecvTime = time.Now() | 665 | payInfo.uncompressedBytes = d |
387 | inPayload.Payload = m | ||
388 | // TODO truncate large payload. | ||
389 | inPayload.Data = d | ||
390 | inPayload.Length = len(d) | ||
391 | } | 666 | } |
392 | return nil | 667 | return nil |
393 | } | 668 | } |
394 | 669 | ||
395 | type rpcInfo struct { | 670 | type rpcInfo struct { |
396 | bytesSent bool | 671 | failfast bool |
397 | bytesReceived bool | ||
398 | } | 672 | } |
399 | 673 | ||
400 | type rpcInfoContextKey struct{} | 674 | type rpcInfoContextKey struct{} |
401 | 675 | ||
402 | func newContextWithRPCInfo(ctx context.Context) context.Context { | 676 | func newContextWithRPCInfo(ctx context.Context, failfast bool) context.Context { |
403 | return context.WithValue(ctx, rpcInfoContextKey{}, &rpcInfo{}) | 677 | return context.WithValue(ctx, rpcInfoContextKey{}, &rpcInfo{failfast: failfast}) |
404 | } | 678 | } |
405 | 679 | ||
406 | func rpcInfoFromContext(ctx context.Context) (s *rpcInfo, ok bool) { | 680 | func rpcInfoFromContext(ctx context.Context) (s *rpcInfo, ok bool) { |
@@ -408,117 +682,135 @@ func rpcInfoFromContext(ctx context.Context) (s *rpcInfo, ok bool) { | |||
408 | return | 682 | return |
409 | } | 683 | } |
410 | 684 | ||
411 | func updateRPCInfoInContext(ctx context.Context, s rpcInfo) { | ||
412 | if ss, ok := rpcInfoFromContext(ctx); ok { | ||
413 | *ss = s | ||
414 | } | ||
415 | return | ||
416 | } | ||
417 | |||
418 | // Code returns the error code for err if it was produced by the rpc system. | 685 | // Code returns the error code for err if it was produced by the rpc system. |
419 | // Otherwise, it returns codes.Unknown. | 686 | // Otherwise, it returns codes.Unknown. |
420 | // | 687 | // |
421 | // Deprecated; use status.FromError and Code method instead. | 688 | // Deprecated: use status.Code instead. |
422 | func Code(err error) codes.Code { | 689 | func Code(err error) codes.Code { |
423 | if s, ok := status.FromError(err); ok { | 690 | return status.Code(err) |
424 | return s.Code() | ||
425 | } | ||
426 | return codes.Unknown | ||
427 | } | 691 | } |
428 | 692 | ||
429 | // ErrorDesc returns the error description of err if it was produced by the rpc system. | 693 | // ErrorDesc returns the error description of err if it was produced by the rpc system. |
430 | // Otherwise, it returns err.Error() or empty string when err is nil. | 694 | // Otherwise, it returns err.Error() or empty string when err is nil. |
431 | // | 695 | // |
432 | // Deprecated; use status.FromError and Message method instead. | 696 | // Deprecated: use status.Convert and Message method instead. |
433 | func ErrorDesc(err error) string { | 697 | func ErrorDesc(err error) string { |
434 | if s, ok := status.FromError(err); ok { | 698 | return status.Convert(err).Message() |
435 | return s.Message() | ||
436 | } | ||
437 | return err.Error() | ||
438 | } | 699 | } |
439 | 700 | ||
440 | // Errorf returns an error containing an error code and a description; | 701 | // Errorf returns an error containing an error code and a description; |
441 | // Errorf returns nil if c is OK. | 702 | // Errorf returns nil if c is OK. |
442 | // | 703 | // |
443 | // Deprecated; use status.Errorf instead. | 704 | // Deprecated: use status.Errorf instead. |
444 | func Errorf(c codes.Code, format string, a ...interface{}) error { | 705 | func Errorf(c codes.Code, format string, a ...interface{}) error { |
445 | return status.Errorf(c, format, a...) | 706 | return status.Errorf(c, format, a...) |
446 | } | 707 | } |
447 | 708 | ||
448 | // MethodConfig defines the configuration recommended by the service providers for a | 709 | // toRPCErr converts an error into an error from the status package. |
449 | // particular method. | 710 | func toRPCErr(err error) error { |
450 | // This is EXPERIMENTAL and subject to change. | 711 | if err == nil || err == io.EOF { |
451 | type MethodConfig struct { | 712 | return err |
452 | // WaitForReady indicates whether RPCs sent to this method should wait until | 713 | } |
453 | // the connection is ready by default (!failfast). The value specified via the | 714 | if err == io.ErrUnexpectedEOF { |
454 | // gRPC client API will override the value set here. | 715 | return status.Error(codes.Internal, err.Error()) |
455 | WaitForReady *bool | 716 | } |
456 | // Timeout is the default timeout for RPCs sent to this method. The actual | 717 | if _, ok := status.FromError(err); ok { |
457 | // deadline used will be the minimum of the value specified here and the value | 718 | return err |
458 | // set by the application via the gRPC client API. If either one is not set, | 719 | } |
459 | // then the other will be used. If neither is set, then the RPC has no deadline. | 720 | switch e := err.(type) { |
460 | Timeout *time.Duration | 721 | case transport.ConnectionError: |
461 | // MaxReqSize is the maximum allowed payload size for an individual request in a | 722 | return status.Error(codes.Unavailable, e.Desc) |
462 | // stream (client->server) in bytes. The size which is measured is the serialized | 723 | default: |
463 | // payload after per-message compression (but before stream compression) in bytes. | 724 | switch err { |
464 | // The actual value used is the minumum of the value specified here and the value set | 725 | case context.DeadlineExceeded: |
465 | // by the application via the gRPC client API. If either one is not set, then the other | 726 | return status.Error(codes.DeadlineExceeded, err.Error()) |
466 | // will be used. If neither is set, then the built-in default is used. | 727 | case context.Canceled: |
467 | MaxReqSize *int | 728 | return status.Error(codes.Canceled, err.Error()) |
468 | // MaxRespSize is the maximum allowed payload size for an individual response in a | 729 | } |
469 | // stream (server->client) in bytes. | 730 | } |
470 | MaxRespSize *int | 731 | return status.Error(codes.Unknown, err.Error()) |
471 | } | 732 | } |
472 | |||
473 | // ServiceConfig is provided by the service provider and contains parameters for how | ||
474 | // clients that connect to the service should behave. | ||
475 | // This is EXPERIMENTAL and subject to change. | ||
476 | type ServiceConfig struct { | ||
477 | // LB is the load balancer the service providers recommends. The balancer specified | ||
478 | // via grpc.WithBalancer will override this. | ||
479 | LB Balancer | ||
480 | // Methods contains a map for the methods in this service. | ||
481 | // If there is an exact match for a method (i.e. /service/method) in the map, use the corresponding MethodConfig. | ||
482 | // If there's no exact match, look for the default config for the service (/service/) and use the corresponding MethodConfig if it exists. | ||
483 | // Otherwise, the method has no MethodConfig to use. | ||
484 | Methods map[string]MethodConfig | ||
485 | } | ||
486 | |||
487 | func min(a, b *int) *int { | ||
488 | if *a < *b { | ||
489 | return a | ||
490 | } | ||
491 | return b | ||
492 | } | ||
493 | |||
494 | func getMaxSize(mcMax, doptMax *int, defaultVal int) *int { | ||
495 | if mcMax == nil && doptMax == nil { | ||
496 | return &defaultVal | ||
497 | } | ||
498 | if mcMax != nil && doptMax != nil { | ||
499 | return min(mcMax, doptMax) | ||
500 | } | ||
501 | if mcMax != nil { | ||
502 | return mcMax | ||
503 | } | ||
504 | return doptMax | ||
505 | } | ||
506 | |||
507 | // SupportPackageIsVersion3 is referenced from generated protocol buffer files. | ||
508 | // The latest support package version is 4. | ||
509 | // SupportPackageIsVersion3 is kept for compability. It will be removed in the | ||
510 | // next support package version update. | ||
511 | const SupportPackageIsVersion3 = true | ||
512 | |||
513 | // SupportPackageIsVersion4 is referenced from generated protocol buffer files | ||
514 | // to assert that that code is compatible with this version of the grpc package. | ||
515 | // | ||
516 | // This constant may be renamed in the future if a change in the generated code | ||
517 | // requires a synchronised update of grpc-go and protoc-gen-go. This constant | ||
518 | // should not be referenced from any other code. | ||
519 | const SupportPackageIsVersion4 = true | ||
520 | 733 | ||
521 | // Version is the current grpc version. | 734 | // setCallInfoCodec should only be called after CallOptions have been applied. |
522 | const Version = "1.6.0-dev" | 735 | func setCallInfoCodec(c *callInfo) error { |
736 | if c.codec != nil { | ||
737 | // codec was already set by a CallOption; use it. | ||
738 | return nil | ||
739 | } | ||
740 | |||
741 | if c.contentSubtype == "" { | ||
742 | // No codec specified in CallOptions; use proto by default. | ||
743 | c.codec = encoding.GetCodec(proto.Name) | ||
744 | return nil | ||
745 | } | ||
746 | |||
747 | // c.contentSubtype is already lowercased in CallContentSubtype | ||
748 | c.codec = encoding.GetCodec(c.contentSubtype) | ||
749 | if c.codec == nil { | ||
750 | return status.Errorf(codes.Internal, "no codec registered for content-subtype %s", c.contentSubtype) | ||
751 | } | ||
752 | return nil | ||
753 | } | ||
754 | |||
755 | // parseDialTarget returns the network and address to pass to dialer | ||
756 | func parseDialTarget(target string) (net string, addr string) { | ||
757 | net = "tcp" | ||
758 | |||
759 | m1 := strings.Index(target, ":") | ||
760 | m2 := strings.Index(target, ":/") | ||
761 | |||
762 | // handle unix:addr which will fail with url.Parse | ||
763 | if m1 >= 0 && m2 < 0 { | ||
764 | if n := target[0:m1]; n == "unix" { | ||
765 | net = n | ||
766 | addr = target[m1+1:] | ||
767 | return net, addr | ||
768 | } | ||
769 | } | ||
770 | if m2 >= 0 { | ||
771 | t, err := url.Parse(target) | ||
772 | if err != nil { | ||
773 | return net, target | ||
774 | } | ||
775 | scheme := t.Scheme | ||
776 | addr = t.Path | ||
777 | if scheme == "unix" { | ||
778 | net = scheme | ||
779 | if addr == "" { | ||
780 | addr = t.Host | ||
781 | } | ||
782 | return net, addr | ||
783 | } | ||
784 | } | ||
785 | |||
786 | return net, target | ||
787 | } | ||
788 | |||
789 | // channelzData is used to store channelz related data for ClientConn, addrConn and Server. | ||
790 | // These fields cannot be embedded in the original structs (e.g. ClientConn), since to do atomic | ||
791 | // operation on int64 variable on 32-bit machine, user is responsible to enforce memory alignment. | ||
792 | // Here, by grouping those int64 fields inside a struct, we are enforcing the alignment. | ||
793 | type channelzData struct { | ||
794 | callsStarted int64 | ||
795 | callsFailed int64 | ||
796 | callsSucceeded int64 | ||
797 | // lastCallStartedTime stores the timestamp that last call starts. It is of int64 type instead of | ||
798 | // time.Time since it's more costly to atomically update time.Time variable than int64 variable. | ||
799 | lastCallStartedTime int64 | ||
800 | } | ||
801 | |||
802 | // The SupportPackageIsVersion variables are referenced from generated protocol | ||
803 | // buffer files to ensure compatibility with the gRPC version used. The latest | ||
804 | // support package version is 5. | ||
805 | // | ||
806 | // Older versions are kept for compatibility. They may be removed if | ||
807 | // compatibility cannot be maintained. | ||
808 | // | ||
809 | // These constants should not be referenced from any other code. | ||
810 | const ( | ||
811 | SupportPackageIsVersion3 = true | ||
812 | SupportPackageIsVersion4 = true | ||
813 | SupportPackageIsVersion5 = true | ||
814 | ) | ||
523 | 815 | ||
524 | const grpcUA = "grpc-go/" + Version | 816 | const grpcUA = "grpc-go/" + Version |
diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 42733e2..d705d7a 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go | |||
@@ -19,36 +19,41 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "context" |
23 | "errors" | 23 | "errors" |
24 | "fmt" | 24 | "fmt" |
25 | "io" | 25 | "io" |
26 | "math" | ||
26 | "net" | 27 | "net" |
27 | "net/http" | 28 | "net/http" |
28 | "reflect" | 29 | "reflect" |
29 | "runtime" | 30 | "runtime" |
30 | "strings" | 31 | "strings" |
31 | "sync" | 32 | "sync" |
33 | "sync/atomic" | ||
32 | "time" | 34 | "time" |
33 | 35 | ||
34 | "golang.org/x/net/context" | ||
35 | "golang.org/x/net/http2" | ||
36 | "golang.org/x/net/trace" | 36 | "golang.org/x/net/trace" |
37 | |||
37 | "google.golang.org/grpc/codes" | 38 | "google.golang.org/grpc/codes" |
38 | "google.golang.org/grpc/credentials" | 39 | "google.golang.org/grpc/credentials" |
40 | "google.golang.org/grpc/encoding" | ||
41 | "google.golang.org/grpc/encoding/proto" | ||
39 | "google.golang.org/grpc/grpclog" | 42 | "google.golang.org/grpc/grpclog" |
40 | "google.golang.org/grpc/internal" | 43 | "google.golang.org/grpc/internal/binarylog" |
44 | "google.golang.org/grpc/internal/channelz" | ||
45 | "google.golang.org/grpc/internal/transport" | ||
41 | "google.golang.org/grpc/keepalive" | 46 | "google.golang.org/grpc/keepalive" |
42 | "google.golang.org/grpc/metadata" | 47 | "google.golang.org/grpc/metadata" |
48 | "google.golang.org/grpc/peer" | ||
43 | "google.golang.org/grpc/stats" | 49 | "google.golang.org/grpc/stats" |
44 | "google.golang.org/grpc/status" | 50 | "google.golang.org/grpc/status" |
45 | "google.golang.org/grpc/tap" | 51 | "google.golang.org/grpc/tap" |
46 | "google.golang.org/grpc/transport" | ||
47 | ) | 52 | ) |
48 | 53 | ||
49 | const ( | 54 | const ( |
50 | defaultServerMaxReceiveMessageSize = 1024 * 1024 * 4 | 55 | defaultServerMaxReceiveMessageSize = 1024 * 1024 * 4 |
51 | defaultServerMaxSendMessageSize = 1024 * 1024 * 4 | 56 | defaultServerMaxSendMessageSize = math.MaxInt32 |
52 | ) | 57 | ) |
53 | 58 | ||
54 | type methodHandler func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor UnaryServerInterceptor) (interface{}, error) | 59 | type methodHandler func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor UnaryServerInterceptor) (interface{}, error) |
@@ -88,18 +93,24 @@ type Server struct { | |||
88 | conns map[io.Closer]bool | 93 | conns map[io.Closer]bool |
89 | serve bool | 94 | serve bool |
90 | drain bool | 95 | drain bool |
91 | ctx context.Context | 96 | cv *sync.Cond // signaled when connections close for GracefulStop |
92 | cancel context.CancelFunc | ||
93 | // A CondVar to let GracefulStop() blocks until all the pending RPCs are finished | ||
94 | // and all the transport goes away. | ||
95 | cv *sync.Cond | ||
96 | m map[string]*service // service name -> service info | 97 | m map[string]*service // service name -> service info |
97 | events trace.EventLog | 98 | events trace.EventLog |
99 | |||
100 | quit chan struct{} | ||
101 | done chan struct{} | ||
102 | quitOnce sync.Once | ||
103 | doneOnce sync.Once | ||
104 | channelzRemoveOnce sync.Once | ||
105 | serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop | ||
106 | |||
107 | channelzID int64 // channelz unique identification number | ||
108 | czData *channelzData | ||
98 | } | 109 | } |
99 | 110 | ||
100 | type options struct { | 111 | type options struct { |
101 | creds credentials.TransportCredentials | 112 | creds credentials.TransportCredentials |
102 | codec Codec | 113 | codec baseCodec |
103 | cp Compressor | 114 | cp Compressor |
104 | dc Decompressor | 115 | dc Decompressor |
105 | unaryInt UnaryServerInterceptor | 116 | unaryInt UnaryServerInterceptor |
@@ -109,22 +120,50 @@ type options struct { | |||
109 | maxConcurrentStreams uint32 | 120 | maxConcurrentStreams uint32 |
110 | maxReceiveMessageSize int | 121 | maxReceiveMessageSize int |
111 | maxSendMessageSize int | 122 | maxSendMessageSize int |
112 | useHandlerImpl bool // use http.Handler-based server | ||
113 | unknownStreamDesc *StreamDesc | 123 | unknownStreamDesc *StreamDesc |
114 | keepaliveParams keepalive.ServerParameters | 124 | keepaliveParams keepalive.ServerParameters |
115 | keepalivePolicy keepalive.EnforcementPolicy | 125 | keepalivePolicy keepalive.EnforcementPolicy |
116 | initialWindowSize int32 | 126 | initialWindowSize int32 |
117 | initialConnWindowSize int32 | 127 | initialConnWindowSize int32 |
128 | writeBufferSize int | ||
129 | readBufferSize int | ||
130 | connectionTimeout time.Duration | ||
131 | maxHeaderListSize *uint32 | ||
118 | } | 132 | } |
119 | 133 | ||
120 | var defaultServerOptions = options{ | 134 | var defaultServerOptions = options{ |
121 | maxReceiveMessageSize: defaultServerMaxReceiveMessageSize, | 135 | maxReceiveMessageSize: defaultServerMaxReceiveMessageSize, |
122 | maxSendMessageSize: defaultServerMaxSendMessageSize, | 136 | maxSendMessageSize: defaultServerMaxSendMessageSize, |
137 | connectionTimeout: 120 * time.Second, | ||
138 | writeBufferSize: defaultWriteBufSize, | ||
139 | readBufferSize: defaultReadBufSize, | ||
123 | } | 140 | } |
124 | 141 | ||
125 | // A ServerOption sets options such as credentials, codec and keepalive parameters, etc. | 142 | // A ServerOption sets options such as credentials, codec and keepalive parameters, etc. |
126 | type ServerOption func(*options) | 143 | type ServerOption func(*options) |
127 | 144 | ||
145 | // WriteBufferSize determines how much data can be batched before doing a write on the wire. | ||
146 | // The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. | ||
147 | // The default value for this buffer is 32KB. | ||
148 | // Zero will disable the write buffer such that each write will be on underlying connection. | ||
149 | // Note: A Send call may not directly translate to a write. | ||
150 | func WriteBufferSize(s int) ServerOption { | ||
151 | return func(o *options) { | ||
152 | o.writeBufferSize = s | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // ReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most | ||
157 | // for one read syscall. | ||
158 | // The default value for this buffer is 32KB. | ||
159 | // Zero will disable read buffer for a connection so data framer can access the underlying | ||
160 | // conn directly. | ||
161 | func ReadBufferSize(s int) ServerOption { | ||
162 | return func(o *options) { | ||
163 | o.readBufferSize = s | ||
164 | } | ||
165 | } | ||
166 | |||
128 | // InitialWindowSize returns a ServerOption that sets window size for stream. | 167 | // InitialWindowSize returns a ServerOption that sets window size for stream. |
129 | // The lower bound for window size is 64K and any value smaller than that will be ignored. | 168 | // The lower bound for window size is 64K and any value smaller than that will be ignored. |
130 | func InitialWindowSize(s int32) ServerOption { | 169 | func InitialWindowSize(s int32) ServerOption { |
@@ -156,20 +195,32 @@ func KeepaliveEnforcementPolicy(kep keepalive.EnforcementPolicy) ServerOption { | |||
156 | } | 195 | } |
157 | 196 | ||
158 | // CustomCodec returns a ServerOption that sets a codec for message marshaling and unmarshaling. | 197 | // CustomCodec returns a ServerOption that sets a codec for message marshaling and unmarshaling. |
198 | // | ||
199 | // This will override any lookups by content-subtype for Codecs registered with RegisterCodec. | ||
159 | func CustomCodec(codec Codec) ServerOption { | 200 | func CustomCodec(codec Codec) ServerOption { |
160 | return func(o *options) { | 201 | return func(o *options) { |
161 | o.codec = codec | 202 | o.codec = codec |
162 | } | 203 | } |
163 | } | 204 | } |
164 | 205 | ||
165 | // RPCCompressor returns a ServerOption that sets a compressor for outbound messages. | 206 | // RPCCompressor returns a ServerOption that sets a compressor for outbound |
207 | // messages. For backward compatibility, all outbound messages will be sent | ||
208 | // using this compressor, regardless of incoming message compression. By | ||
209 | // default, server messages will be sent using the same compressor with which | ||
210 | // request messages were sent. | ||
211 | // | ||
212 | // Deprecated: use encoding.RegisterCompressor instead. | ||
166 | func RPCCompressor(cp Compressor) ServerOption { | 213 | func RPCCompressor(cp Compressor) ServerOption { |
167 | return func(o *options) { | 214 | return func(o *options) { |
168 | o.cp = cp | 215 | o.cp = cp |
169 | } | 216 | } |
170 | } | 217 | } |
171 | 218 | ||
172 | // RPCDecompressor returns a ServerOption that sets a decompressor for inbound messages. | 219 | // RPCDecompressor returns a ServerOption that sets a decompressor for inbound |
220 | // messages. It has higher priority than decompressors registered via | ||
221 | // encoding.RegisterCompressor. | ||
222 | // | ||
223 | // Deprecated: use encoding.RegisterCompressor instead. | ||
173 | func RPCDecompressor(dc Decompressor) ServerOption { | 224 | func RPCDecompressor(dc Decompressor) ServerOption { |
174 | return func(o *options) { | 225 | return func(o *options) { |
175 | o.dc = dc | 226 | o.dc = dc |
@@ -177,7 +228,9 @@ func RPCDecompressor(dc Decompressor) ServerOption { | |||
177 | } | 228 | } |
178 | 229 | ||
179 | // MaxMsgSize returns a ServerOption to set the max message size in bytes the server can receive. | 230 | // MaxMsgSize returns a ServerOption to set the max message size in bytes the server can receive. |
180 | // If this is not set, gRPC uses the default limit. Deprecated: use MaxRecvMsgSize instead. | 231 | // If this is not set, gRPC uses the default limit. |
232 | // | ||
233 | // Deprecated: use MaxRecvMsgSize instead. | ||
181 | func MaxMsgSize(m int) ServerOption { | 234 | func MaxMsgSize(m int) ServerOption { |
182 | return MaxRecvMsgSize(m) | 235 | return MaxRecvMsgSize(m) |
183 | } | 236 | } |
@@ -259,7 +312,7 @@ func StatsHandler(h stats.Handler) ServerOption { | |||
259 | // handler that will be invoked instead of returning the "unimplemented" gRPC | 312 | // handler that will be invoked instead of returning the "unimplemented" gRPC |
260 | // error whenever a request is received for an unregistered service or method. | 313 | // error whenever a request is received for an unregistered service or method. |
261 | // The handling function has full access to the Context of the request and the | 314 | // The handling function has full access to the Context of the request and the |
262 | // stream, and the invocation passes through interceptors. | 315 | // stream, and the invocation bypasses interceptors. |
263 | func UnknownServiceHandler(streamHandler StreamHandler) ServerOption { | 316 | func UnknownServiceHandler(streamHandler StreamHandler) ServerOption { |
264 | return func(o *options) { | 317 | return func(o *options) { |
265 | o.unknownStreamDesc = &StreamDesc{ | 318 | o.unknownStreamDesc = &StreamDesc{ |
@@ -272,6 +325,26 @@ func UnknownServiceHandler(streamHandler StreamHandler) ServerOption { | |||
272 | } | 325 | } |
273 | } | 326 | } |
274 | 327 | ||
328 | // ConnectionTimeout returns a ServerOption that sets the timeout for | ||
329 | // connection establishment (up to and including HTTP/2 handshaking) for all | ||
330 | // new connections. If this is not set, the default is 120 seconds. A zero or | ||
331 | // negative value will result in an immediate timeout. | ||
332 | // | ||
333 | // This API is EXPERIMENTAL. | ||
334 | func ConnectionTimeout(d time.Duration) ServerOption { | ||
335 | return func(o *options) { | ||
336 | o.connectionTimeout = d | ||
337 | } | ||
338 | } | ||
339 | |||
340 | // MaxHeaderListSize returns a ServerOption that sets the max (uncompressed) size | ||
341 | // of header list that the server is prepared to accept. | ||
342 | func MaxHeaderListSize(s uint32) ServerOption { | ||
343 | return func(o *options) { | ||
344 | o.maxHeaderListSize = &s | ||
345 | } | ||
346 | } | ||
347 | |||
275 | // NewServer creates a gRPC server which has no service registered and has not | 348 | // NewServer creates a gRPC server which has no service registered and has not |
276 | // started to accept requests yet. | 349 | // started to accept requests yet. |
277 | func NewServer(opt ...ServerOption) *Server { | 350 | func NewServer(opt ...ServerOption) *Server { |
@@ -279,22 +352,24 @@ func NewServer(opt ...ServerOption) *Server { | |||
279 | for _, o := range opt { | 352 | for _, o := range opt { |
280 | o(&opts) | 353 | o(&opts) |
281 | } | 354 | } |
282 | if opts.codec == nil { | ||
283 | // Set the default codec. | ||
284 | opts.codec = protoCodec{} | ||
285 | } | ||
286 | s := &Server{ | 355 | s := &Server{ |
287 | lis: make(map[net.Listener]bool), | 356 | lis: make(map[net.Listener]bool), |
288 | opts: opts, | 357 | opts: opts, |
289 | conns: make(map[io.Closer]bool), | 358 | conns: make(map[io.Closer]bool), |
290 | m: make(map[string]*service), | 359 | m: make(map[string]*service), |
360 | quit: make(chan struct{}), | ||
361 | done: make(chan struct{}), | ||
362 | czData: new(channelzData), | ||
291 | } | 363 | } |
292 | s.cv = sync.NewCond(&s.mu) | 364 | s.cv = sync.NewCond(&s.mu) |
293 | s.ctx, s.cancel = context.WithCancel(context.Background()) | ||
294 | if EnableTracing { | 365 | if EnableTracing { |
295 | _, file, line, _ := runtime.Caller(1) | 366 | _, file, line, _ := runtime.Caller(1) |
296 | s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line)) | 367 | s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line)) |
297 | } | 368 | } |
369 | |||
370 | if channelz.IsOn() { | ||
371 | s.channelzID = channelz.RegisterServer(&channelzServer{s}, "") | ||
372 | } | ||
298 | return s | 373 | return s |
299 | } | 374 | } |
300 | 375 | ||
@@ -399,11 +474,9 @@ func (s *Server) GetServiceInfo() map[string]ServiceInfo { | |||
399 | return ret | 474 | return ret |
400 | } | 475 | } |
401 | 476 | ||
402 | var ( | 477 | // ErrServerStopped indicates that the operation is now illegal because of |
403 | // ErrServerStopped indicates that the operation is now illegal because of | 478 | // the server being stopped. |
404 | // the server being stopped. | 479 | var ErrServerStopped = errors.New("grpc: the server has been stopped") |
405 | ErrServerStopped = errors.New("grpc: the server has been stopped") | ||
406 | ) | ||
407 | 480 | ||
408 | func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { | 481 | func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { |
409 | if s.opts.creds == nil { | 482 | if s.opts.creds == nil { |
@@ -412,28 +485,67 @@ func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credenti | |||
412 | return s.opts.creds.ServerHandshake(rawConn) | 485 | return s.opts.creds.ServerHandshake(rawConn) |
413 | } | 486 | } |
414 | 487 | ||
488 | type listenSocket struct { | ||
489 | net.Listener | ||
490 | channelzID int64 | ||
491 | } | ||
492 | |||
493 | func (l *listenSocket) ChannelzMetric() *channelz.SocketInternalMetric { | ||
494 | return &channelz.SocketInternalMetric{ | ||
495 | SocketOptions: channelz.GetSocketOption(l.Listener), | ||
496 | LocalAddr: l.Listener.Addr(), | ||
497 | } | ||
498 | } | ||
499 | |||
500 | func (l *listenSocket) Close() error { | ||
501 | err := l.Listener.Close() | ||
502 | if channelz.IsOn() { | ||
503 | channelz.RemoveEntry(l.channelzID) | ||
504 | } | ||
505 | return err | ||
506 | } | ||
507 | |||
415 | // Serve accepts incoming connections on the listener lis, creating a new | 508 | // Serve accepts incoming connections on the listener lis, creating a new |
416 | // ServerTransport and service goroutine for each. The service goroutines | 509 | // ServerTransport and service goroutine for each. The service goroutines |
417 | // read gRPC requests and then call the registered handlers to reply to them. | 510 | // read gRPC requests and then call the registered handlers to reply to them. |
418 | // Serve returns when lis.Accept fails with fatal errors. lis will be closed when | 511 | // Serve returns when lis.Accept fails with fatal errors. lis will be closed when |
419 | // this method returns. | 512 | // this method returns. |
420 | // Serve always returns non-nil error. | 513 | // Serve will return a non-nil error unless Stop or GracefulStop is called. |
421 | func (s *Server) Serve(lis net.Listener) error { | 514 | func (s *Server) Serve(lis net.Listener) error { |
422 | s.mu.Lock() | 515 | s.mu.Lock() |
423 | s.printf("serving") | 516 | s.printf("serving") |
424 | s.serve = true | 517 | s.serve = true |
425 | if s.lis == nil { | 518 | if s.lis == nil { |
519 | // Serve called after Stop or GracefulStop. | ||
426 | s.mu.Unlock() | 520 | s.mu.Unlock() |
427 | lis.Close() | 521 | lis.Close() |
428 | return ErrServerStopped | 522 | return ErrServerStopped |
429 | } | 523 | } |
430 | s.lis[lis] = true | 524 | |
525 | s.serveWG.Add(1) | ||
526 | defer func() { | ||
527 | s.serveWG.Done() | ||
528 | select { | ||
529 | // Stop or GracefulStop called; block until done and return nil. | ||
530 | case <-s.quit: | ||
531 | <-s.done | ||
532 | default: | ||
533 | } | ||
534 | }() | ||
535 | |||
536 | ls := &listenSocket{Listener: lis} | ||
537 | s.lis[ls] = true | ||
538 | |||
539 | if channelz.IsOn() { | ||
540 | ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, lis.Addr().String()) | ||
541 | } | ||
431 | s.mu.Unlock() | 542 | s.mu.Unlock() |
543 | |||
432 | defer func() { | 544 | defer func() { |
433 | s.mu.Lock() | 545 | s.mu.Lock() |
434 | if s.lis != nil && s.lis[lis] { | 546 | if s.lis != nil && s.lis[ls] { |
435 | lis.Close() | 547 | ls.Close() |
436 | delete(s.lis, lis) | 548 | delete(s.lis, ls) |
437 | } | 549 | } |
438 | s.mu.Unlock() | 550 | s.mu.Unlock() |
439 | }() | 551 | }() |
@@ -460,36 +572,52 @@ func (s *Server) Serve(lis net.Listener) error { | |||
460 | timer := time.NewTimer(tempDelay) | 572 | timer := time.NewTimer(tempDelay) |
461 | select { | 573 | select { |
462 | case <-timer.C: | 574 | case <-timer.C: |
463 | case <-s.ctx.Done(): | 575 | case <-s.quit: |
576 | timer.Stop() | ||
577 | return nil | ||
464 | } | 578 | } |
465 | timer.Stop() | ||
466 | continue | 579 | continue |
467 | } | 580 | } |
468 | s.mu.Lock() | 581 | s.mu.Lock() |
469 | s.printf("done serving; Accept = %v", err) | 582 | s.printf("done serving; Accept = %v", err) |
470 | s.mu.Unlock() | 583 | s.mu.Unlock() |
584 | |||
585 | select { | ||
586 | case <-s.quit: | ||
587 | return nil | ||
588 | default: | ||
589 | } | ||
471 | return err | 590 | return err |
472 | } | 591 | } |
473 | tempDelay = 0 | 592 | tempDelay = 0 |
474 | // Start a new goroutine to deal with rawConn | 593 | // Start a new goroutine to deal with rawConn so we don't stall this Accept |
475 | // so we don't stall this Accept loop goroutine. | 594 | // loop goroutine. |
476 | go s.handleRawConn(rawConn) | 595 | // |
596 | // Make sure we account for the goroutine so GracefulStop doesn't nil out | ||
597 | // s.conns before this conn can be added. | ||
598 | s.serveWG.Add(1) | ||
599 | go func() { | ||
600 | s.handleRawConn(rawConn) | ||
601 | s.serveWG.Done() | ||
602 | }() | ||
477 | } | 603 | } |
478 | } | 604 | } |
479 | 605 | ||
480 | // handleRawConn is run in its own goroutine and handles a just-accepted | 606 | // handleRawConn forks a goroutine to handle a just-accepted connection that |
481 | // connection that has not had any I/O performed on it yet. | 607 | // has not had any I/O performed on it yet. |
482 | func (s *Server) handleRawConn(rawConn net.Conn) { | 608 | func (s *Server) handleRawConn(rawConn net.Conn) { |
609 | rawConn.SetDeadline(time.Now().Add(s.opts.connectionTimeout)) | ||
483 | conn, authInfo, err := s.useTransportAuthenticator(rawConn) | 610 | conn, authInfo, err := s.useTransportAuthenticator(rawConn) |
484 | if err != nil { | 611 | if err != nil { |
485 | s.mu.Lock() | 612 | s.mu.Lock() |
486 | s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) | 613 | s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) |
487 | s.mu.Unlock() | 614 | s.mu.Unlock() |
488 | grpclog.Warningf("grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err) | 615 | grpclog.Warningf("grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err) |
489 | // If serverHandShake returns ErrConnDispatched, keep rawConn open. | 616 | // If serverHandshake returns ErrConnDispatched, keep rawConn open. |
490 | if err != credentials.ErrConnDispatched { | 617 | if err != credentials.ErrConnDispatched { |
491 | rawConn.Close() | 618 | rawConn.Close() |
492 | } | 619 | } |
620 | rawConn.SetDeadline(time.Time{}) | ||
493 | return | 621 | return |
494 | } | 622 | } |
495 | 623 | ||
@@ -501,19 +629,25 @@ func (s *Server) handleRawConn(rawConn net.Conn) { | |||
501 | } | 629 | } |
502 | s.mu.Unlock() | 630 | s.mu.Unlock() |
503 | 631 | ||
504 | if s.opts.useHandlerImpl { | 632 | // Finish handshaking (HTTP2) |
505 | s.serveUsingHandler(conn) | 633 | st := s.newHTTP2Transport(conn, authInfo) |
506 | } else { | 634 | if st == nil { |
507 | s.serveHTTP2Transport(conn, authInfo) | 635 | return |
636 | } | ||
637 | |||
638 | rawConn.SetDeadline(time.Time{}) | ||
639 | if !s.addConn(st) { | ||
640 | return | ||
508 | } | 641 | } |
642 | go func() { | ||
643 | s.serveStreams(st) | ||
644 | s.removeConn(st) | ||
645 | }() | ||
509 | } | 646 | } |
510 | 647 | ||
511 | // serveHTTP2Transport sets up a http/2 transport (using the | 648 | // newHTTP2Transport sets up a http/2 transport (using the |
512 | // gRPC http2 server transport in transport/http2_server.go) and | 649 | // gRPC http2 server transport in transport/http2_server.go). |
513 | // serves streams on it. | 650 | func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) transport.ServerTransport { |
514 | // This is run in its own goroutine (it does network I/O in | ||
515 | // transport.NewServerTransport). | ||
516 | func (s *Server) serveHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) { | ||
517 | config := &transport.ServerConfig{ | 651 | config := &transport.ServerConfig{ |
518 | MaxStreams: s.opts.maxConcurrentStreams, | 652 | MaxStreams: s.opts.maxConcurrentStreams, |
519 | AuthInfo: authInfo, | 653 | AuthInfo: authInfo, |
@@ -523,6 +657,10 @@ func (s *Server) serveHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) | |||
523 | KeepalivePolicy: s.opts.keepalivePolicy, | 657 | KeepalivePolicy: s.opts.keepalivePolicy, |
524 | InitialWindowSize: s.opts.initialWindowSize, | 658 | InitialWindowSize: s.opts.initialWindowSize, |
525 | InitialConnWindowSize: s.opts.initialConnWindowSize, | 659 | InitialConnWindowSize: s.opts.initialConnWindowSize, |
660 | WriteBufferSize: s.opts.writeBufferSize, | ||
661 | ReadBufferSize: s.opts.readBufferSize, | ||
662 | ChannelzParentID: s.channelzID, | ||
663 | MaxHeaderListSize: s.opts.maxHeaderListSize, | ||
526 | } | 664 | } |
527 | st, err := transport.NewServerTransport("http2", c, config) | 665 | st, err := transport.NewServerTransport("http2", c, config) |
528 | if err != nil { | 666 | if err != nil { |
@@ -531,17 +669,13 @@ func (s *Server) serveHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) | |||
531 | s.mu.Unlock() | 669 | s.mu.Unlock() |
532 | c.Close() | 670 | c.Close() |
533 | grpclog.Warningln("grpc: Server.Serve failed to create ServerTransport: ", err) | 671 | grpclog.Warningln("grpc: Server.Serve failed to create ServerTransport: ", err) |
534 | return | 672 | return nil |
535 | } | ||
536 | if !s.addConn(st) { | ||
537 | st.Close() | ||
538 | return | ||
539 | } | 673 | } |
540 | s.serveStreams(st) | 674 | |
675 | return st | ||
541 | } | 676 | } |
542 | 677 | ||
543 | func (s *Server) serveStreams(st transport.ServerTransport) { | 678 | func (s *Server) serveStreams(st transport.ServerTransport) { |
544 | defer s.removeConn(st) | ||
545 | defer st.Close() | 679 | defer st.Close() |
546 | var wg sync.WaitGroup | 680 | var wg sync.WaitGroup |
547 | st.HandleStreams(func(stream *transport.Stream) { | 681 | st.HandleStreams(func(stream *transport.Stream) { |
@@ -562,32 +696,6 @@ func (s *Server) serveStreams(st transport.ServerTransport) { | |||
562 | 696 | ||
563 | var _ http.Handler = (*Server)(nil) | 697 | var _ http.Handler = (*Server)(nil) |
564 | 698 | ||
565 | // serveUsingHandler is called from handleRawConn when s is configured | ||
566 | // to handle requests via the http.Handler interface. It sets up a | ||
567 | // net/http.Server to handle the just-accepted conn. The http.Server | ||
568 | // is configured to route all incoming requests (all HTTP/2 streams) | ||
569 | // to ServeHTTP, which creates a new ServerTransport for each stream. | ||
570 | // serveUsingHandler blocks until conn closes. | ||
571 | // | ||
572 | // This codepath is only used when Server.TestingUseHandlerImpl has | ||
573 | // been configured. This lets the end2end tests exercise the ServeHTTP | ||
574 | // method as one of the environment types. | ||
575 | // | ||
576 | // conn is the *tls.Conn that's already been authenticated. | ||
577 | func (s *Server) serveUsingHandler(conn net.Conn) { | ||
578 | if !s.addConn(conn) { | ||
579 | conn.Close() | ||
580 | return | ||
581 | } | ||
582 | defer s.removeConn(conn) | ||
583 | h2s := &http2.Server{ | ||
584 | MaxConcurrentStreams: s.opts.maxConcurrentStreams, | ||
585 | } | ||
586 | h2s.ServeConn(conn, &http2.ServeConnOpts{ | ||
587 | Handler: s, | ||
588 | }) | ||
589 | } | ||
590 | |||
591 | // ServeHTTP implements the Go standard library's http.Handler | 699 | // ServeHTTP implements the Go standard library's http.Handler |
592 | // interface by responding to the gRPC request r, by looking up | 700 | // interface by responding to the gRPC request r, by looking up |
593 | // the requested gRPC method in the gRPC server s. | 701 | // the requested gRPC method in the gRPC server s. |
@@ -613,13 +721,12 @@ func (s *Server) serveUsingHandler(conn net.Conn) { | |||
613 | // available through grpc-go's HTTP/2 server, and it is currently EXPERIMENTAL | 721 | // available through grpc-go's HTTP/2 server, and it is currently EXPERIMENTAL |
614 | // and subject to change. | 722 | // and subject to change. |
615 | func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 723 | func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
616 | st, err := transport.NewServerHandlerTransport(w, r) | 724 | st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandler) |
617 | if err != nil { | 725 | if err != nil { |
618 | http.Error(w, err.Error(), http.StatusInternalServerError) | 726 | http.Error(w, err.Error(), http.StatusInternalServerError) |
619 | return | 727 | return |
620 | } | 728 | } |
621 | if !s.addConn(st) { | 729 | if !s.addConn(st) { |
622 | st.Close() | ||
623 | return | 730 | return |
624 | } | 731 | } |
625 | defer s.removeConn(st) | 732 | defer s.removeConn(st) |
@@ -649,9 +756,15 @@ func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Strea | |||
649 | func (s *Server) addConn(c io.Closer) bool { | 756 | func (s *Server) addConn(c io.Closer) bool { |
650 | s.mu.Lock() | 757 | s.mu.Lock() |
651 | defer s.mu.Unlock() | 758 | defer s.mu.Unlock() |
652 | if s.conns == nil || s.drain { | 759 | if s.conns == nil { |
760 | c.Close() | ||
653 | return false | 761 | return false |
654 | } | 762 | } |
763 | if s.drain { | ||
764 | // Transport added after we drained our existing conns: drain it | ||
765 | // immediately. | ||
766 | c.(transport.ServerTransport).Drain() | ||
767 | } | ||
655 | s.conns[c] = true | 768 | s.conns[c] = true |
656 | return true | 769 | return true |
657 | } | 770 | } |
@@ -665,43 +778,73 @@ func (s *Server) removeConn(c io.Closer) { | |||
665 | } | 778 | } |
666 | } | 779 | } |
667 | 780 | ||
668 | func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options) error { | 781 | func (s *Server) channelzMetric() *channelz.ServerInternalMetric { |
669 | var ( | 782 | return &channelz.ServerInternalMetric{ |
670 | cbuf *bytes.Buffer | 783 | CallsStarted: atomic.LoadInt64(&s.czData.callsStarted), |
671 | outPayload *stats.OutPayload | 784 | CallsSucceeded: atomic.LoadInt64(&s.czData.callsSucceeded), |
672 | ) | 785 | CallsFailed: atomic.LoadInt64(&s.czData.callsFailed), |
673 | if cp != nil { | 786 | LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&s.czData.lastCallStartedTime)), |
674 | cbuf = new(bytes.Buffer) | ||
675 | } | 787 | } |
676 | if s.opts.statsHandler != nil { | 788 | } |
677 | outPayload = &stats.OutPayload{} | 789 | |
678 | } | 790 | func (s *Server) incrCallsStarted() { |
679 | p, err := encode(s.opts.codec, msg, cp, cbuf, outPayload) | 791 | atomic.AddInt64(&s.czData.callsStarted, 1) |
792 | atomic.StoreInt64(&s.czData.lastCallStartedTime, time.Now().UnixNano()) | ||
793 | } | ||
794 | |||
795 | func (s *Server) incrCallsSucceeded() { | ||
796 | atomic.AddInt64(&s.czData.callsSucceeded, 1) | ||
797 | } | ||
798 | |||
799 | func (s *Server) incrCallsFailed() { | ||
800 | atomic.AddInt64(&s.czData.callsFailed, 1) | ||
801 | } | ||
802 | |||
803 | func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error { | ||
804 | data, err := encode(s.getCodec(stream.ContentSubtype()), msg) | ||
680 | if err != nil { | 805 | if err != nil { |
681 | grpclog.Errorln("grpc: server failed to encode response: ", err) | 806 | grpclog.Errorln("grpc: server failed to encode response: ", err) |
682 | return err | 807 | return err |
683 | } | 808 | } |
684 | if len(p) > s.opts.maxSendMessageSize { | 809 | compData, err := compress(data, cp, comp) |
685 | return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(p), s.opts.maxSendMessageSize) | 810 | if err != nil { |
811 | grpclog.Errorln("grpc: server failed to compress response: ", err) | ||
812 | return err | ||
813 | } | ||
814 | hdr, payload := msgHeader(data, compData) | ||
815 | // TODO(dfawley): should we be checking len(data) instead? | ||
816 | if len(payload) > s.opts.maxSendMessageSize { | ||
817 | return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(payload), s.opts.maxSendMessageSize) | ||
686 | } | 818 | } |
687 | err = t.Write(stream, p, opts) | 819 | err = t.Write(stream, hdr, payload, opts) |
688 | if err == nil && outPayload != nil { | 820 | if err == nil && s.opts.statsHandler != nil { |
689 | outPayload.SentTime = time.Now() | 821 | s.opts.statsHandler.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now())) |
690 | s.opts.statsHandler.HandleRPC(stream.Context(), outPayload) | ||
691 | } | 822 | } |
692 | return err | 823 | return err |
693 | } | 824 | } |
694 | 825 | ||
695 | func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, md *MethodDesc, trInfo *traceInfo) (err error) { | 826 | func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, md *MethodDesc, trInfo *traceInfo) (err error) { |
827 | if channelz.IsOn() { | ||
828 | s.incrCallsStarted() | ||
829 | defer func() { | ||
830 | if err != nil && err != io.EOF { | ||
831 | s.incrCallsFailed() | ||
832 | } else { | ||
833 | s.incrCallsSucceeded() | ||
834 | } | ||
835 | }() | ||
836 | } | ||
696 | sh := s.opts.statsHandler | 837 | sh := s.opts.statsHandler |
697 | if sh != nil { | 838 | if sh != nil { |
839 | beginTime := time.Now() | ||
698 | begin := &stats.Begin{ | 840 | begin := &stats.Begin{ |
699 | BeginTime: time.Now(), | 841 | BeginTime: beginTime, |
700 | } | 842 | } |
701 | sh.HandleRPC(stream.Context(), begin) | 843 | sh.HandleRPC(stream.Context(), begin) |
702 | defer func() { | 844 | defer func() { |
703 | end := &stats.End{ | 845 | end := &stats.End{ |
704 | EndTime: time.Now(), | 846 | BeginTime: beginTime, |
847 | EndTime: time.Now(), | ||
705 | } | 848 | } |
706 | if err != nil && err != io.EOF { | 849 | if err != nil && err != io.EOF { |
707 | end.Error = toRPCErr(err) | 850 | end.Error = toRPCErr(err) |
@@ -720,94 +863,112 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. | |||
720 | } | 863 | } |
721 | }() | 864 | }() |
722 | } | 865 | } |
723 | if s.opts.cp != nil { | 866 | |
724 | // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686. | 867 | binlog := binarylog.GetMethodLogger(stream.Method()) |
725 | stream.SetSendCompress(s.opts.cp.Type()) | 868 | if binlog != nil { |
869 | ctx := stream.Context() | ||
870 | md, _ := metadata.FromIncomingContext(ctx) | ||
871 | logEntry := &binarylog.ClientHeader{ | ||
872 | Header: md, | ||
873 | MethodName: stream.Method(), | ||
874 | PeerAddr: nil, | ||
875 | } | ||
876 | if deadline, ok := ctx.Deadline(); ok { | ||
877 | logEntry.Timeout = deadline.Sub(time.Now()) | ||
878 | if logEntry.Timeout < 0 { | ||
879 | logEntry.Timeout = 0 | ||
880 | } | ||
881 | } | ||
882 | if a := md[":authority"]; len(a) > 0 { | ||
883 | logEntry.Authority = a[0] | ||
884 | } | ||
885 | if peer, ok := peer.FromContext(ctx); ok { | ||
886 | logEntry.PeerAddr = peer.Addr | ||
887 | } | ||
888 | binlog.Log(logEntry) | ||
889 | } | ||
890 | |||
891 | // comp and cp are used for compression. decomp and dc are used for | ||
892 | // decompression. If comp and decomp are both set, they are the same; | ||
893 | // however they are kept separate to ensure that at most one of the | ||
894 | // compressor/decompressor variable pairs are set for use later. | ||
895 | var comp, decomp encoding.Compressor | ||
896 | var cp Compressor | ||
897 | var dc Decompressor | ||
898 | |||
899 | // If dc is set and matches the stream's compression, use it. Otherwise, try | ||
900 | // to find a matching registered compressor for decomp. | ||
901 | if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc { | ||
902 | dc = s.opts.dc | ||
903 | } else if rc != "" && rc != encoding.Identity { | ||
904 | decomp = encoding.GetCompressor(rc) | ||
905 | if decomp == nil { | ||
906 | st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc) | ||
907 | t.WriteStatus(stream, st) | ||
908 | return st.Err() | ||
909 | } | ||
726 | } | 910 | } |
727 | p := &parser{r: stream} | 911 | |
728 | pf, req, err := p.recvMsg(s.opts.maxReceiveMessageSize) | 912 | // If cp is set, use it. Otherwise, attempt to compress the response using |
729 | if err == io.EOF { | 913 | // the incoming message compression method. |
730 | // The entire stream is done (for unary RPC only). | 914 | // |
731 | return err | 915 | // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686. |
916 | if s.opts.cp != nil { | ||
917 | cp = s.opts.cp | ||
918 | stream.SetSendCompress(cp.Type()) | ||
919 | } else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity { | ||
920 | // Legacy compressor not specified; attempt to respond with same encoding. | ||
921 | comp = encoding.GetCompressor(rc) | ||
922 | if comp != nil { | ||
923 | stream.SetSendCompress(rc) | ||
924 | } | ||
732 | } | 925 | } |
733 | if err == io.ErrUnexpectedEOF { | 926 | |
734 | err = Errorf(codes.Internal, io.ErrUnexpectedEOF.Error()) | 927 | var payInfo *payloadInfo |
928 | if sh != nil || binlog != nil { | ||
929 | payInfo = &payloadInfo{} | ||
735 | } | 930 | } |
931 | d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) | ||
736 | if err != nil { | 932 | if err != nil { |
737 | if st, ok := status.FromError(err); ok { | 933 | if st, ok := status.FromError(err); ok { |
738 | if e := t.WriteStatus(stream, st); e != nil { | 934 | if e := t.WriteStatus(stream, st); e != nil { |
739 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) | 935 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) |
740 | } | 936 | } |
741 | } else { | ||
742 | switch st := err.(type) { | ||
743 | case transport.ConnectionError: | ||
744 | // Nothing to do here. | ||
745 | case transport.StreamError: | ||
746 | if e := t.WriteStatus(stream, status.New(st.Code, st.Desc)); e != nil { | ||
747 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) | ||
748 | } | ||
749 | default: | ||
750 | panic(fmt.Sprintf("grpc: Unexpected error (%T) from recvMsg: %v", st, st)) | ||
751 | } | ||
752 | } | 937 | } |
753 | return err | 938 | return err |
754 | } | 939 | } |
755 | 940 | if channelz.IsOn() { | |
756 | if err := checkRecvPayload(pf, stream.RecvCompress(), s.opts.dc); err != nil { | 941 | t.IncrMsgRecv() |
757 | if st, ok := status.FromError(err); ok { | ||
758 | if e := t.WriteStatus(stream, st); e != nil { | ||
759 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) | ||
760 | } | ||
761 | return err | ||
762 | } | ||
763 | if e := t.WriteStatus(stream, status.New(codes.Internal, err.Error())); e != nil { | ||
764 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) | ||
765 | } | ||
766 | |||
767 | // TODO checkRecvPayload always return RPC error. Add a return here if necessary. | ||
768 | } | ||
769 | var inPayload *stats.InPayload | ||
770 | if sh != nil { | ||
771 | inPayload = &stats.InPayload{ | ||
772 | RecvTime: time.Now(), | ||
773 | } | ||
774 | } | 942 | } |
775 | df := func(v interface{}) error { | 943 | df := func(v interface{}) error { |
776 | if inPayload != nil { | 944 | if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil { |
777 | inPayload.WireLength = len(req) | ||
778 | } | ||
779 | if pf == compressionMade { | ||
780 | var err error | ||
781 | req, err = s.opts.dc.Do(bytes.NewReader(req)) | ||
782 | if err != nil { | ||
783 | return Errorf(codes.Internal, err.Error()) | ||
784 | } | ||
785 | } | ||
786 | if len(req) > s.opts.maxReceiveMessageSize { | ||
787 | // TODO: Revisit the error code. Currently keep it consistent with | ||
788 | // java implementation. | ||
789 | return status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(req), s.opts.maxReceiveMessageSize) | ||
790 | } | ||
791 | if err := s.opts.codec.Unmarshal(req, v); err != nil { | ||
792 | return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err) | 945 | return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err) |
793 | } | 946 | } |
794 | if inPayload != nil { | 947 | if sh != nil { |
795 | inPayload.Payload = v | 948 | sh.HandleRPC(stream.Context(), &stats.InPayload{ |
796 | inPayload.Data = req | 949 | RecvTime: time.Now(), |
797 | inPayload.Length = len(req) | 950 | Payload: v, |
798 | sh.HandleRPC(stream.Context(), inPayload) | 951 | Data: d, |
952 | Length: len(d), | ||
953 | }) | ||
954 | } | ||
955 | if binlog != nil { | ||
956 | binlog.Log(&binarylog.ClientMessage{ | ||
957 | Message: d, | ||
958 | }) | ||
799 | } | 959 | } |
800 | if trInfo != nil { | 960 | if trInfo != nil { |
801 | trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true) | 961 | trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true) |
802 | } | 962 | } |
803 | return nil | 963 | return nil |
804 | } | 964 | } |
805 | reply, appErr := md.Handler(srv.server, stream.Context(), df, s.opts.unaryInt) | 965 | ctx := NewContextWithServerTransportStream(stream.Context(), stream) |
966 | reply, appErr := md.Handler(srv.server, ctx, df, s.opts.unaryInt) | ||
806 | if appErr != nil { | 967 | if appErr != nil { |
807 | appStatus, ok := status.FromError(appErr) | 968 | appStatus, ok := status.FromError(appErr) |
808 | if !ok { | 969 | if !ok { |
809 | // Convert appErr if it is not a grpc status error. | 970 | // Convert appErr if it is not a grpc status error. |
810 | appErr = status.Error(convertCode(appErr), appErr.Error()) | 971 | appErr = status.Error(codes.Unknown, appErr.Error()) |
811 | appStatus, _ = status.FromError(appErr) | 972 | appStatus, _ = status.FromError(appErr) |
812 | } | 973 | } |
813 | if trInfo != nil { | 974 | if trInfo != nil { |
@@ -817,16 +978,27 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. | |||
817 | if e := t.WriteStatus(stream, appStatus); e != nil { | 978 | if e := t.WriteStatus(stream, appStatus); e != nil { |
818 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status: %v", e) | 979 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status: %v", e) |
819 | } | 980 | } |
981 | if binlog != nil { | ||
982 | if h, _ := stream.Header(); h.Len() > 0 { | ||
983 | // Only log serverHeader if there was header. Otherwise it can | ||
984 | // be trailer only. | ||
985 | binlog.Log(&binarylog.ServerHeader{ | ||
986 | Header: h, | ||
987 | }) | ||
988 | } | ||
989 | binlog.Log(&binarylog.ServerTrailer{ | ||
990 | Trailer: stream.Trailer(), | ||
991 | Err: appErr, | ||
992 | }) | ||
993 | } | ||
820 | return appErr | 994 | return appErr |
821 | } | 995 | } |
822 | if trInfo != nil { | 996 | if trInfo != nil { |
823 | trInfo.tr.LazyLog(stringer("OK"), false) | 997 | trInfo.tr.LazyLog(stringer("OK"), false) |
824 | } | 998 | } |
825 | opts := &transport.Options{ | 999 | opts := &transport.Options{Last: true} |
826 | Last: true, | 1000 | |
827 | Delay: false, | 1001 | if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil { |
828 | } | ||
829 | if err := s.sendResponse(t, stream, reply, s.opts.cp, opts); err != nil { | ||
830 | if err == io.EOF { | 1002 | if err == io.EOF { |
831 | // The entire stream is done (for unary RPC only). | 1003 | // The entire stream is done (for unary RPC only). |
832 | return err | 1004 | return err |
@@ -839,35 +1011,72 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. | |||
839 | switch st := err.(type) { | 1011 | switch st := err.(type) { |
840 | case transport.ConnectionError: | 1012 | case transport.ConnectionError: |
841 | // Nothing to do here. | 1013 | // Nothing to do here. |
842 | case transport.StreamError: | ||
843 | if e := t.WriteStatus(stream, status.New(st.Code, st.Desc)); e != nil { | ||
844 | grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) | ||
845 | } | ||
846 | default: | 1014 | default: |
847 | panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st)) | 1015 | panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st)) |
848 | } | 1016 | } |
849 | } | 1017 | } |
1018 | if binlog != nil { | ||
1019 | h, _ := stream.Header() | ||
1020 | binlog.Log(&binarylog.ServerHeader{ | ||
1021 | Header: h, | ||
1022 | }) | ||
1023 | binlog.Log(&binarylog.ServerTrailer{ | ||
1024 | Trailer: stream.Trailer(), | ||
1025 | Err: appErr, | ||
1026 | }) | ||
1027 | } | ||
850 | return err | 1028 | return err |
851 | } | 1029 | } |
1030 | if binlog != nil { | ||
1031 | h, _ := stream.Header() | ||
1032 | binlog.Log(&binarylog.ServerHeader{ | ||
1033 | Header: h, | ||
1034 | }) | ||
1035 | binlog.Log(&binarylog.ServerMessage{ | ||
1036 | Message: reply, | ||
1037 | }) | ||
1038 | } | ||
1039 | if channelz.IsOn() { | ||
1040 | t.IncrMsgSent() | ||
1041 | } | ||
852 | if trInfo != nil { | 1042 | if trInfo != nil { |
853 | trInfo.tr.LazyLog(&payload{sent: true, msg: reply}, true) | 1043 | trInfo.tr.LazyLog(&payload{sent: true, msg: reply}, true) |
854 | } | 1044 | } |
855 | // TODO: Should we be logging if writing status failed here, like above? | 1045 | // TODO: Should we be logging if writing status failed here, like above? |
856 | // Should the logging be in WriteStatus? Should we ignore the WriteStatus | 1046 | // Should the logging be in WriteStatus? Should we ignore the WriteStatus |
857 | // error or allow the stats handler to see it? | 1047 | // error or allow the stats handler to see it? |
858 | return t.WriteStatus(stream, status.New(codes.OK, "")) | 1048 | err = t.WriteStatus(stream, status.New(codes.OK, "")) |
1049 | if binlog != nil { | ||
1050 | binlog.Log(&binarylog.ServerTrailer{ | ||
1051 | Trailer: stream.Trailer(), | ||
1052 | Err: appErr, | ||
1053 | }) | ||
1054 | } | ||
1055 | return err | ||
859 | } | 1056 | } |
860 | 1057 | ||
861 | func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc, trInfo *traceInfo) (err error) { | 1058 | func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc, trInfo *traceInfo) (err error) { |
1059 | if channelz.IsOn() { | ||
1060 | s.incrCallsStarted() | ||
1061 | defer func() { | ||
1062 | if err != nil && err != io.EOF { | ||
1063 | s.incrCallsFailed() | ||
1064 | } else { | ||
1065 | s.incrCallsSucceeded() | ||
1066 | } | ||
1067 | }() | ||
1068 | } | ||
862 | sh := s.opts.statsHandler | 1069 | sh := s.opts.statsHandler |
863 | if sh != nil { | 1070 | if sh != nil { |
1071 | beginTime := time.Now() | ||
864 | begin := &stats.Begin{ | 1072 | begin := &stats.Begin{ |
865 | BeginTime: time.Now(), | 1073 | BeginTime: beginTime, |
866 | } | 1074 | } |
867 | sh.HandleRPC(stream.Context(), begin) | 1075 | sh.HandleRPC(stream.Context(), begin) |
868 | defer func() { | 1076 | defer func() { |
869 | end := &stats.End{ | 1077 | end := &stats.End{ |
870 | EndTime: time.Now(), | 1078 | BeginTime: beginTime, |
1079 | EndTime: time.Now(), | ||
871 | } | 1080 | } |
872 | if err != nil && err != io.EOF { | 1081 | if err != nil && err != io.EOF { |
873 | end.Error = toRPCErr(err) | 1082 | end.Error = toRPCErr(err) |
@@ -875,24 +1084,70 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp | |||
875 | sh.HandleRPC(stream.Context(), end) | 1084 | sh.HandleRPC(stream.Context(), end) |
876 | }() | 1085 | }() |
877 | } | 1086 | } |
878 | if s.opts.cp != nil { | 1087 | ctx := NewContextWithServerTransportStream(stream.Context(), stream) |
879 | stream.SetSendCompress(s.opts.cp.Type()) | ||
880 | } | ||
881 | ss := &serverStream{ | 1088 | ss := &serverStream{ |
882 | t: t, | 1089 | ctx: ctx, |
883 | s: stream, | 1090 | t: t, |
884 | p: &parser{r: stream}, | 1091 | s: stream, |
885 | codec: s.opts.codec, | 1092 | p: &parser{r: stream}, |
886 | cp: s.opts.cp, | 1093 | codec: s.getCodec(stream.ContentSubtype()), |
887 | dc: s.opts.dc, | ||
888 | maxReceiveMessageSize: s.opts.maxReceiveMessageSize, | 1094 | maxReceiveMessageSize: s.opts.maxReceiveMessageSize, |
889 | maxSendMessageSize: s.opts.maxSendMessageSize, | 1095 | maxSendMessageSize: s.opts.maxSendMessageSize, |
890 | trInfo: trInfo, | 1096 | trInfo: trInfo, |
891 | statsHandler: sh, | 1097 | statsHandler: sh, |
892 | } | 1098 | } |
893 | if ss.cp != nil { | 1099 | |
894 | ss.cbuf = new(bytes.Buffer) | 1100 | ss.binlog = binarylog.GetMethodLogger(stream.Method()) |
1101 | if ss.binlog != nil { | ||
1102 | md, _ := metadata.FromIncomingContext(ctx) | ||
1103 | logEntry := &binarylog.ClientHeader{ | ||
1104 | Header: md, | ||
1105 | MethodName: stream.Method(), | ||
1106 | PeerAddr: nil, | ||
1107 | } | ||
1108 | if deadline, ok := ctx.Deadline(); ok { | ||
1109 | logEntry.Timeout = deadline.Sub(time.Now()) | ||
1110 | if logEntry.Timeout < 0 { | ||
1111 | logEntry.Timeout = 0 | ||
1112 | } | ||
1113 | } | ||
1114 | if a := md[":authority"]; len(a) > 0 { | ||
1115 | logEntry.Authority = a[0] | ||
1116 | } | ||
1117 | if peer, ok := peer.FromContext(ss.Context()); ok { | ||
1118 | logEntry.PeerAddr = peer.Addr | ||
1119 | } | ||
1120 | ss.binlog.Log(logEntry) | ||
1121 | } | ||
1122 | |||
1123 | // If dc is set and matches the stream's compression, use it. Otherwise, try | ||
1124 | // to find a matching registered compressor for decomp. | ||
1125 | if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc { | ||
1126 | ss.dc = s.opts.dc | ||
1127 | } else if rc != "" && rc != encoding.Identity { | ||
1128 | ss.decomp = encoding.GetCompressor(rc) | ||
1129 | if ss.decomp == nil { | ||
1130 | st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc) | ||
1131 | t.WriteStatus(ss.s, st) | ||
1132 | return st.Err() | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | // If cp is set, use it. Otherwise, attempt to compress the response using | ||
1137 | // the incoming message compression method. | ||
1138 | // | ||
1139 | // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686. | ||
1140 | if s.opts.cp != nil { | ||
1141 | ss.cp = s.opts.cp | ||
1142 | stream.SetSendCompress(s.opts.cp.Type()) | ||
1143 | } else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity { | ||
1144 | // Legacy compressor not specified; attempt to respond with same encoding. | ||
1145 | ss.comp = encoding.GetCompressor(rc) | ||
1146 | if ss.comp != nil { | ||
1147 | stream.SetSendCompress(rc) | ||
1148 | } | ||
895 | } | 1149 | } |
1150 | |||
896 | if trInfo != nil { | 1151 | if trInfo != nil { |
897 | trInfo.tr.LazyLog(&trInfo.firstLine, false) | 1152 | trInfo.tr.LazyLog(&trInfo.firstLine, false) |
898 | defer func() { | 1153 | defer func() { |
@@ -924,12 +1179,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp | |||
924 | if appErr != nil { | 1179 | if appErr != nil { |
925 | appStatus, ok := status.FromError(appErr) | 1180 | appStatus, ok := status.FromError(appErr) |
926 | if !ok { | 1181 | if !ok { |
927 | switch err := appErr.(type) { | 1182 | appStatus = status.New(codes.Unknown, appErr.Error()) |
928 | case transport.StreamError: | ||
929 | appStatus = status.New(err.Code, err.Desc) | ||
930 | default: | ||
931 | appStatus = status.New(convertCode(appErr), appErr.Error()) | ||
932 | } | ||
933 | appErr = appStatus.Err() | 1183 | appErr = appStatus.Err() |
934 | } | 1184 | } |
935 | if trInfo != nil { | 1185 | if trInfo != nil { |
@@ -939,6 +1189,12 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp | |||
939 | ss.mu.Unlock() | 1189 | ss.mu.Unlock() |
940 | } | 1190 | } |
941 | t.WriteStatus(ss.s, appStatus) | 1191 | t.WriteStatus(ss.s, appStatus) |
1192 | if ss.binlog != nil { | ||
1193 | ss.binlog.Log(&binarylog.ServerTrailer{ | ||
1194 | Trailer: ss.s.Trailer(), | ||
1195 | Err: appErr, | ||
1196 | }) | ||
1197 | } | ||
942 | // TODO: Should we log an error from WriteStatus here and below? | 1198 | // TODO: Should we log an error from WriteStatus here and below? |
943 | return appErr | 1199 | return appErr |
944 | } | 1200 | } |
@@ -947,8 +1203,14 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp | |||
947 | ss.trInfo.tr.LazyLog(stringer("OK"), false) | 1203 | ss.trInfo.tr.LazyLog(stringer("OK"), false) |
948 | ss.mu.Unlock() | 1204 | ss.mu.Unlock() |
949 | } | 1205 | } |
950 | return t.WriteStatus(ss.s, status.New(codes.OK, "")) | 1206 | err = t.WriteStatus(ss.s, status.New(codes.OK, "")) |
951 | 1207 | if ss.binlog != nil { | |
1208 | ss.binlog.Log(&binarylog.ServerTrailer{ | ||
1209 | Trailer: ss.s.Trailer(), | ||
1210 | Err: appErr, | ||
1211 | }) | ||
1212 | } | ||
1213 | return err | ||
952 | } | 1214 | } |
953 | 1215 | ||
954 | func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) { | 1216 | func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) { |
@@ -977,47 +1239,27 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str | |||
977 | } | 1239 | } |
978 | service := sm[:pos] | 1240 | service := sm[:pos] |
979 | method := sm[pos+1:] | 1241 | method := sm[pos+1:] |
980 | srv, ok := s.m[service] | 1242 | |
981 | if !ok { | 1243 | if srv, ok := s.m[service]; ok { |
982 | if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { | 1244 | if md, ok := srv.md[method]; ok { |
983 | s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) | 1245 | s.processUnaryRPC(t, stream, srv, md, trInfo) |
984 | return | 1246 | return |
985 | } | 1247 | } |
986 | if trInfo != nil { | 1248 | if sd, ok := srv.sd[method]; ok { |
987 | trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true) | 1249 | s.processStreamingRPC(t, stream, srv, sd, trInfo) |
988 | trInfo.tr.SetError() | 1250 | return |
989 | } | ||
990 | errDesc := fmt.Sprintf("unknown service %v", service) | ||
991 | if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { | ||
992 | if trInfo != nil { | ||
993 | trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) | ||
994 | trInfo.tr.SetError() | ||
995 | } | ||
996 | grpclog.Warningf("grpc: Server.handleStream failed to write status: %v", err) | ||
997 | } | ||
998 | if trInfo != nil { | ||
999 | trInfo.tr.Finish() | ||
1000 | } | 1251 | } |
1001 | return | ||
1002 | } | ||
1003 | // Unary RPC or Streaming RPC? | ||
1004 | if md, ok := srv.md[method]; ok { | ||
1005 | s.processUnaryRPC(t, stream, srv, md, trInfo) | ||
1006 | return | ||
1007 | } | 1252 | } |
1008 | if sd, ok := srv.sd[method]; ok { | 1253 | // Unknown service, or known server unknown method. |
1009 | s.processStreamingRPC(t, stream, srv, sd, trInfo) | 1254 | if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { |
1255 | s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) | ||
1010 | return | 1256 | return |
1011 | } | 1257 | } |
1012 | if trInfo != nil { | 1258 | if trInfo != nil { |
1013 | trInfo.tr.LazyLog(&fmtStringer{"Unknown method %v", []interface{}{method}}, true) | 1259 | trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true) |
1014 | trInfo.tr.SetError() | 1260 | trInfo.tr.SetError() |
1015 | } | 1261 | } |
1016 | if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { | 1262 | errDesc := fmt.Sprintf("unknown service %v", service) |
1017 | s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) | ||
1018 | return | ||
1019 | } | ||
1020 | errDesc := fmt.Sprintf("unknown method %v", method) | ||
1021 | if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { | 1263 | if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { |
1022 | if trInfo != nil { | 1264 | if trInfo != nil { |
1023 | trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) | 1265 | trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) |
@@ -1030,12 +1272,65 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str | |||
1030 | } | 1272 | } |
1031 | } | 1273 | } |
1032 | 1274 | ||
1275 | // The key to save ServerTransportStream in the context. | ||
1276 | type streamKey struct{} | ||
1277 | |||
1278 | // NewContextWithServerTransportStream creates a new context from ctx and | ||
1279 | // attaches stream to it. | ||
1280 | // | ||
1281 | // This API is EXPERIMENTAL. | ||
1282 | func NewContextWithServerTransportStream(ctx context.Context, stream ServerTransportStream) context.Context { | ||
1283 | return context.WithValue(ctx, streamKey{}, stream) | ||
1284 | } | ||
1285 | |||
1286 | // ServerTransportStream is a minimal interface that a transport stream must | ||
1287 | // implement. This can be used to mock an actual transport stream for tests of | ||
1288 | // handler code that use, for example, grpc.SetHeader (which requires some | ||
1289 | // stream to be in context). | ||
1290 | // | ||
1291 | // See also NewContextWithServerTransportStream. | ||
1292 | // | ||
1293 | // This API is EXPERIMENTAL. | ||
1294 | type ServerTransportStream interface { | ||
1295 | Method() string | ||
1296 | SetHeader(md metadata.MD) error | ||
1297 | SendHeader(md metadata.MD) error | ||
1298 | SetTrailer(md metadata.MD) error | ||
1299 | } | ||
1300 | |||
1301 | // ServerTransportStreamFromContext returns the ServerTransportStream saved in | ||
1302 | // ctx. Returns nil if the given context has no stream associated with it | ||
1303 | // (which implies it is not an RPC invocation context). | ||
1304 | // | ||
1305 | // This API is EXPERIMENTAL. | ||
1306 | func ServerTransportStreamFromContext(ctx context.Context) ServerTransportStream { | ||
1307 | s, _ := ctx.Value(streamKey{}).(ServerTransportStream) | ||
1308 | return s | ||
1309 | } | ||
1310 | |||
1033 | // Stop stops the gRPC server. It immediately closes all open | 1311 | // Stop stops the gRPC server. It immediately closes all open |
1034 | // connections and listeners. | 1312 | // connections and listeners. |
1035 | // It cancels all active RPCs on the server side and the corresponding | 1313 | // It cancels all active RPCs on the server side and the corresponding |
1036 | // pending RPCs on the client side will get notified by connection | 1314 | // pending RPCs on the client side will get notified by connection |
1037 | // errors. | 1315 | // errors. |
1038 | func (s *Server) Stop() { | 1316 | func (s *Server) Stop() { |
1317 | s.quitOnce.Do(func() { | ||
1318 | close(s.quit) | ||
1319 | }) | ||
1320 | |||
1321 | defer func() { | ||
1322 | s.serveWG.Wait() | ||
1323 | s.doneOnce.Do(func() { | ||
1324 | close(s.done) | ||
1325 | }) | ||
1326 | }() | ||
1327 | |||
1328 | s.channelzRemoveOnce.Do(func() { | ||
1329 | if channelz.IsOn() { | ||
1330 | channelz.RemoveEntry(s.channelzID) | ||
1331 | } | ||
1332 | }) | ||
1333 | |||
1039 | s.mu.Lock() | 1334 | s.mu.Lock() |
1040 | listeners := s.lis | 1335 | listeners := s.lis |
1041 | s.lis = nil | 1336 | s.lis = nil |
@@ -1053,7 +1348,6 @@ func (s *Server) Stop() { | |||
1053 | } | 1348 | } |
1054 | 1349 | ||
1055 | s.mu.Lock() | 1350 | s.mu.Lock() |
1056 | s.cancel() | ||
1057 | if s.events != nil { | 1351 | if s.events != nil { |
1058 | s.events.Finish() | 1352 | s.events.Finish() |
1059 | s.events = nil | 1353 | s.events = nil |
@@ -1065,22 +1359,44 @@ func (s *Server) Stop() { | |||
1065 | // accepting new connections and RPCs and blocks until all the pending RPCs are | 1359 | // accepting new connections and RPCs and blocks until all the pending RPCs are |
1066 | // finished. | 1360 | // finished. |
1067 | func (s *Server) GracefulStop() { | 1361 | func (s *Server) GracefulStop() { |
1362 | s.quitOnce.Do(func() { | ||
1363 | close(s.quit) | ||
1364 | }) | ||
1365 | |||
1366 | defer func() { | ||
1367 | s.doneOnce.Do(func() { | ||
1368 | close(s.done) | ||
1369 | }) | ||
1370 | }() | ||
1371 | |||
1372 | s.channelzRemoveOnce.Do(func() { | ||
1373 | if channelz.IsOn() { | ||
1374 | channelz.RemoveEntry(s.channelzID) | ||
1375 | } | ||
1376 | }) | ||
1068 | s.mu.Lock() | 1377 | s.mu.Lock() |
1069 | defer s.mu.Unlock() | ||
1070 | if s.conns == nil { | 1378 | if s.conns == nil { |
1379 | s.mu.Unlock() | ||
1071 | return | 1380 | return |
1072 | } | 1381 | } |
1382 | |||
1073 | for lis := range s.lis { | 1383 | for lis := range s.lis { |
1074 | lis.Close() | 1384 | lis.Close() |
1075 | } | 1385 | } |
1076 | s.lis = nil | 1386 | s.lis = nil |
1077 | s.cancel() | ||
1078 | if !s.drain { | 1387 | if !s.drain { |
1079 | for c := range s.conns { | 1388 | for c := range s.conns { |
1080 | c.(transport.ServerTransport).Drain() | 1389 | c.(transport.ServerTransport).Drain() |
1081 | } | 1390 | } |
1082 | s.drain = true | 1391 | s.drain = true |
1083 | } | 1392 | } |
1393 | |||
1394 | // Wait for serving threads to be ready to exit. Only then can we be sure no | ||
1395 | // new conns will be created. | ||
1396 | s.mu.Unlock() | ||
1397 | s.serveWG.Wait() | ||
1398 | s.mu.Lock() | ||
1399 | |||
1084 | for len(s.conns) != 0 { | 1400 | for len(s.conns) != 0 { |
1085 | s.cv.Wait() | 1401 | s.cv.Wait() |
1086 | } | 1402 | } |
@@ -1089,26 +1405,23 @@ func (s *Server) GracefulStop() { | |||
1089 | s.events.Finish() | 1405 | s.events.Finish() |
1090 | s.events = nil | 1406 | s.events = nil |
1091 | } | 1407 | } |
1408 | s.mu.Unlock() | ||
1092 | } | 1409 | } |
1093 | 1410 | ||
1094 | func init() { | 1411 | // contentSubtype must be lowercase |
1095 | internal.TestingCloseConns = func(arg interface{}) { | 1412 | // cannot return nil |
1096 | arg.(*Server).testingCloseConns() | 1413 | func (s *Server) getCodec(contentSubtype string) baseCodec { |
1414 | if s.opts.codec != nil { | ||
1415 | return s.opts.codec | ||
1097 | } | 1416 | } |
1098 | internal.TestingUseHandlerImpl = func(arg interface{}) { | 1417 | if contentSubtype == "" { |
1099 | arg.(*Server).opts.useHandlerImpl = true | 1418 | return encoding.GetCodec(proto.Name) |
1100 | } | 1419 | } |
1101 | } | 1420 | codec := encoding.GetCodec(contentSubtype) |
1102 | 1421 | if codec == nil { | |
1103 | // testingCloseConns closes all existing transports but keeps s.lis | 1422 | return encoding.GetCodec(proto.Name) |
1104 | // accepting new connections. | ||
1105 | func (s *Server) testingCloseConns() { | ||
1106 | s.mu.Lock() | ||
1107 | for c := range s.conns { | ||
1108 | c.Close() | ||
1109 | delete(s.conns, c) | ||
1110 | } | 1423 | } |
1111 | s.mu.Unlock() | 1424 | return codec |
1112 | } | 1425 | } |
1113 | 1426 | ||
1114 | // SetHeader sets the header metadata. | 1427 | // SetHeader sets the header metadata. |
@@ -1121,9 +1434,9 @@ func SetHeader(ctx context.Context, md metadata.MD) error { | |||
1121 | if md.Len() == 0 { | 1434 | if md.Len() == 0 { |
1122 | return nil | 1435 | return nil |
1123 | } | 1436 | } |
1124 | stream, ok := transport.StreamFromContext(ctx) | 1437 | stream := ServerTransportStreamFromContext(ctx) |
1125 | if !ok { | 1438 | if stream == nil { |
1126 | return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) | 1439 | return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) |
1127 | } | 1440 | } |
1128 | return stream.SetHeader(md) | 1441 | return stream.SetHeader(md) |
1129 | } | 1442 | } |
@@ -1131,15 +1444,11 @@ func SetHeader(ctx context.Context, md metadata.MD) error { | |||
1131 | // SendHeader sends header metadata. It may be called at most once. | 1444 | // SendHeader sends header metadata. It may be called at most once. |
1132 | // The provided md and headers set by SetHeader() will be sent. | 1445 | // The provided md and headers set by SetHeader() will be sent. |
1133 | func SendHeader(ctx context.Context, md metadata.MD) error { | 1446 | func SendHeader(ctx context.Context, md metadata.MD) error { |
1134 | stream, ok := transport.StreamFromContext(ctx) | 1447 | stream := ServerTransportStreamFromContext(ctx) |
1135 | if !ok { | 1448 | if stream == nil { |
1136 | return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) | 1449 | return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) |
1137 | } | 1450 | } |
1138 | t := stream.ServerTransport() | 1451 | if err := stream.SendHeader(md); err != nil { |
1139 | if t == nil { | ||
1140 | grpclog.Fatalf("grpc: SendHeader: %v has no ServerTransport to send header metadata.", stream) | ||
1141 | } | ||
1142 | if err := t.WriteHeader(stream, md); err != nil { | ||
1143 | return toRPCErr(err) | 1452 | return toRPCErr(err) |
1144 | } | 1453 | } |
1145 | return nil | 1454 | return nil |
@@ -1151,9 +1460,27 @@ func SetTrailer(ctx context.Context, md metadata.MD) error { | |||
1151 | if md.Len() == 0 { | 1460 | if md.Len() == 0 { |
1152 | return nil | 1461 | return nil |
1153 | } | 1462 | } |
1154 | stream, ok := transport.StreamFromContext(ctx) | 1463 | stream := ServerTransportStreamFromContext(ctx) |
1155 | if !ok { | 1464 | if stream == nil { |
1156 | return Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) | 1465 | return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx) |
1157 | } | 1466 | } |
1158 | return stream.SetTrailer(md) | 1467 | return stream.SetTrailer(md) |
1159 | } | 1468 | } |
1469 | |||
1470 | // Method returns the method string for the server context. The returned | ||
1471 | // string is in the format of "/service/method". | ||
1472 | func Method(ctx context.Context) (string, bool) { | ||
1473 | s := ServerTransportStreamFromContext(ctx) | ||
1474 | if s == nil { | ||
1475 | return "", false | ||
1476 | } | ||
1477 | return s.Method(), true | ||
1478 | } | ||
1479 | |||
1480 | type channelzServer struct { | ||
1481 | s *Server | ||
1482 | } | ||
1483 | |||
1484 | func (c *channelzServer) ChannelzMetric() *channelz.ServerInternalMetric { | ||
1485 | return c.s.channelzMetric() | ||
1486 | } | ||
diff --git a/vendor/google.golang.org/grpc/service_config.go b/vendor/google.golang.org/grpc/service_config.go new file mode 100644 index 0000000..162857e --- /dev/null +++ b/vendor/google.golang.org/grpc/service_config.go | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package grpc | ||
20 | |||
21 | import ( | ||
22 | "encoding/json" | ||
23 | "fmt" | ||
24 | "strconv" | ||
25 | "strings" | ||
26 | "time" | ||
27 | |||
28 | "google.golang.org/grpc/codes" | ||
29 | "google.golang.org/grpc/grpclog" | ||
30 | ) | ||
31 | |||
32 | const maxInt = int(^uint(0) >> 1) | ||
33 | |||
34 | // MethodConfig defines the configuration recommended by the service providers for a | ||
35 | // particular method. | ||
36 | // | ||
37 | // Deprecated: Users should not use this struct. Service config should be received | ||
38 | // through name resolver, as specified here | ||
39 | // https://github.com/grpc/grpc/blob/master/doc/service_config.md | ||
40 | type MethodConfig struct { | ||
41 | // WaitForReady indicates whether RPCs sent to this method should wait until | ||
42 | // the connection is ready by default (!failfast). The value specified via the | ||
43 | // gRPC client API will override the value set here. | ||
44 | WaitForReady *bool | ||
45 | // Timeout is the default timeout for RPCs sent to this method. The actual | ||
46 | // deadline used will be the minimum of the value specified here and the value | ||
47 | // set by the application via the gRPC client API. If either one is not set, | ||
48 | // then the other will be used. If neither is set, then the RPC has no deadline. | ||
49 | Timeout *time.Duration | ||
50 | // MaxReqSize is the maximum allowed payload size for an individual request in a | ||
51 | // stream (client->server) in bytes. The size which is measured is the serialized | ||
52 | // payload after per-message compression (but before stream compression) in bytes. | ||
53 | // The actual value used is the minimum of the value specified here and the value set | ||
54 | // by the application via the gRPC client API. If either one is not set, then the other | ||
55 | // will be used. If neither is set, then the built-in default is used. | ||
56 | MaxReqSize *int | ||
57 | // MaxRespSize is the maximum allowed payload size for an individual response in a | ||
58 | // stream (server->client) in bytes. | ||
59 | MaxRespSize *int | ||
60 | // RetryPolicy configures retry options for the method. | ||
61 | retryPolicy *retryPolicy | ||
62 | } | ||
63 | |||
64 | // ServiceConfig is provided by the service provider and contains parameters for how | ||
65 | // clients that connect to the service should behave. | ||
66 | // | ||
67 | // Deprecated: Users should not use this struct. Service config should be received | ||
68 | // through name resolver, as specified here | ||
69 | // https://github.com/grpc/grpc/blob/master/doc/service_config.md | ||
70 | type ServiceConfig struct { | ||
71 | // LB is the load balancer the service providers recommends. The balancer specified | ||
72 | // via grpc.WithBalancer will override this. | ||
73 | LB *string | ||
74 | |||
75 | // Methods contains a map for the methods in this service. If there is an | ||
76 | // exact match for a method (i.e. /service/method) in the map, use the | ||
77 | // corresponding MethodConfig. If there's no exact match, look for the | ||
78 | // default config for the service (/service/) and use the corresponding | ||
79 | // MethodConfig if it exists. Otherwise, the method has no MethodConfig to | ||
80 | // use. | ||
81 | Methods map[string]MethodConfig | ||
82 | |||
83 | // If a retryThrottlingPolicy is provided, gRPC will automatically throttle | ||
84 | // retry attempts and hedged RPCs when the client’s ratio of failures to | ||
85 | // successes exceeds a threshold. | ||
86 | // | ||
87 | // For each server name, the gRPC client will maintain a token_count which is | ||
88 | // initially set to maxTokens, and can take values between 0 and maxTokens. | ||
89 | // | ||
90 | // Every outgoing RPC (regardless of service or method invoked) will change | ||
91 | // token_count as follows: | ||
92 | // | ||
93 | // - Every failed RPC will decrement the token_count by 1. | ||
94 | // - Every successful RPC will increment the token_count by tokenRatio. | ||
95 | // | ||
96 | // If token_count is less than or equal to maxTokens / 2, then RPCs will not | ||
97 | // be retried and hedged RPCs will not be sent. | ||
98 | retryThrottling *retryThrottlingPolicy | ||
99 | // healthCheckConfig must be set as one of the requirement to enable LB channel | ||
100 | // health check. | ||
101 | healthCheckConfig *healthCheckConfig | ||
102 | } | ||
103 | |||
104 | // healthCheckConfig defines the go-native version of the LB channel health check config. | ||
105 | type healthCheckConfig struct { | ||
106 | // serviceName is the service name to use in the health-checking request. | ||
107 | ServiceName string | ||
108 | } | ||
109 | |||
110 | // retryPolicy defines the go-native version of the retry policy defined by the | ||
111 | // service config here: | ||
112 | // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config | ||
113 | type retryPolicy struct { | ||
114 | // MaxAttempts is the maximum number of attempts, including the original RPC. | ||
115 | // | ||
116 | // This field is required and must be two or greater. | ||
117 | maxAttempts int | ||
118 | |||
119 | // Exponential backoff parameters. The initial retry attempt will occur at | ||
120 | // random(0, initialBackoffMS). In general, the nth attempt will occur at | ||
121 | // random(0, | ||
122 | // min(initialBackoffMS*backoffMultiplier**(n-1), maxBackoffMS)). | ||
123 | // | ||
124 | // These fields are required and must be greater than zero. | ||
125 | initialBackoff time.Duration | ||
126 | maxBackoff time.Duration | ||
127 | backoffMultiplier float64 | ||
128 | |||
129 | // The set of status codes which may be retried. | ||
130 | // | ||
131 | // Status codes are specified as strings, e.g., "UNAVAILABLE". | ||
132 | // | ||
133 | // This field is required and must be non-empty. | ||
134 | // Note: a set is used to store this for easy lookup. | ||
135 | retryableStatusCodes map[codes.Code]bool | ||
136 | } | ||
137 | |||
138 | type jsonRetryPolicy struct { | ||
139 | MaxAttempts int | ||
140 | InitialBackoff string | ||
141 | MaxBackoff string | ||
142 | BackoffMultiplier float64 | ||
143 | RetryableStatusCodes []codes.Code | ||
144 | } | ||
145 | |||
146 | // retryThrottlingPolicy defines the go-native version of the retry throttling | ||
147 | // policy defined by the service config here: | ||
148 | // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config | ||
149 | type retryThrottlingPolicy struct { | ||
150 | // The number of tokens starts at maxTokens. The token_count will always be | ||
151 | // between 0 and maxTokens. | ||
152 | // | ||
153 | // This field is required and must be greater than zero. | ||
154 | MaxTokens float64 | ||
155 | // The amount of tokens to add on each successful RPC. Typically this will | ||
156 | // be some number between 0 and 1, e.g., 0.1. | ||
157 | // | ||
158 | // This field is required and must be greater than zero. Up to 3 decimal | ||
159 | // places are supported. | ||
160 | TokenRatio float64 | ||
161 | } | ||
162 | |||
163 | func parseDuration(s *string) (*time.Duration, error) { | ||
164 | if s == nil { | ||
165 | return nil, nil | ||
166 | } | ||
167 | if !strings.HasSuffix(*s, "s") { | ||
168 | return nil, fmt.Errorf("malformed duration %q", *s) | ||
169 | } | ||
170 | ss := strings.SplitN((*s)[:len(*s)-1], ".", 3) | ||
171 | if len(ss) > 2 { | ||
172 | return nil, fmt.Errorf("malformed duration %q", *s) | ||
173 | } | ||
174 | // hasDigits is set if either the whole or fractional part of the number is | ||
175 | // present, since both are optional but one is required. | ||
176 | hasDigits := false | ||
177 | var d time.Duration | ||
178 | if len(ss[0]) > 0 { | ||
179 | i, err := strconv.ParseInt(ss[0], 10, 32) | ||
180 | if err != nil { | ||
181 | return nil, fmt.Errorf("malformed duration %q: %v", *s, err) | ||
182 | } | ||
183 | d = time.Duration(i) * time.Second | ||
184 | hasDigits = true | ||
185 | } | ||
186 | if len(ss) == 2 && len(ss[1]) > 0 { | ||
187 | if len(ss[1]) > 9 { | ||
188 | return nil, fmt.Errorf("malformed duration %q", *s) | ||
189 | } | ||
190 | f, err := strconv.ParseInt(ss[1], 10, 64) | ||
191 | if err != nil { | ||
192 | return nil, fmt.Errorf("malformed duration %q: %v", *s, err) | ||
193 | } | ||
194 | for i := 9; i > len(ss[1]); i-- { | ||
195 | f *= 10 | ||
196 | } | ||
197 | d += time.Duration(f) | ||
198 | hasDigits = true | ||
199 | } | ||
200 | if !hasDigits { | ||
201 | return nil, fmt.Errorf("malformed duration %q", *s) | ||
202 | } | ||
203 | |||
204 | return &d, nil | ||
205 | } | ||
206 | |||
207 | type jsonName struct { | ||
208 | Service *string | ||
209 | Method *string | ||
210 | } | ||
211 | |||
212 | func (j jsonName) generatePath() (string, bool) { | ||
213 | if j.Service == nil { | ||
214 | return "", false | ||
215 | } | ||
216 | res := "/" + *j.Service + "/" | ||
217 | if j.Method != nil { | ||
218 | res += *j.Method | ||
219 | } | ||
220 | return res, true | ||
221 | } | ||
222 | |||
223 | // TODO(lyuxuan): delete this struct after cleaning up old service config implementation. | ||
224 | type jsonMC struct { | ||
225 | Name *[]jsonName | ||
226 | WaitForReady *bool | ||
227 | Timeout *string | ||
228 | MaxRequestMessageBytes *int64 | ||
229 | MaxResponseMessageBytes *int64 | ||
230 | RetryPolicy *jsonRetryPolicy | ||
231 | } | ||
232 | |||
233 | // TODO(lyuxuan): delete this struct after cleaning up old service config implementation. | ||
234 | type jsonSC struct { | ||
235 | LoadBalancingPolicy *string | ||
236 | MethodConfig *[]jsonMC | ||
237 | RetryThrottling *retryThrottlingPolicy | ||
238 | HealthCheckConfig *healthCheckConfig | ||
239 | } | ||
240 | |||
241 | func parseServiceConfig(js string) (ServiceConfig, error) { | ||
242 | if len(js) == 0 { | ||
243 | return ServiceConfig{}, fmt.Errorf("no JSON service config provided") | ||
244 | } | ||
245 | var rsc jsonSC | ||
246 | err := json.Unmarshal([]byte(js), &rsc) | ||
247 | if err != nil { | ||
248 | grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) | ||
249 | return ServiceConfig{}, err | ||
250 | } | ||
251 | sc := ServiceConfig{ | ||
252 | LB: rsc.LoadBalancingPolicy, | ||
253 | Methods: make(map[string]MethodConfig), | ||
254 | retryThrottling: rsc.RetryThrottling, | ||
255 | healthCheckConfig: rsc.HealthCheckConfig, | ||
256 | } | ||
257 | if rsc.MethodConfig == nil { | ||
258 | return sc, nil | ||
259 | } | ||
260 | |||
261 | for _, m := range *rsc.MethodConfig { | ||
262 | if m.Name == nil { | ||
263 | continue | ||
264 | } | ||
265 | d, err := parseDuration(m.Timeout) | ||
266 | if err != nil { | ||
267 | grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) | ||
268 | return ServiceConfig{}, err | ||
269 | } | ||
270 | |||
271 | mc := MethodConfig{ | ||
272 | WaitForReady: m.WaitForReady, | ||
273 | Timeout: d, | ||
274 | } | ||
275 | if mc.retryPolicy, err = convertRetryPolicy(m.RetryPolicy); err != nil { | ||
276 | grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) | ||
277 | return ServiceConfig{}, err | ||
278 | } | ||
279 | if m.MaxRequestMessageBytes != nil { | ||
280 | if *m.MaxRequestMessageBytes > int64(maxInt) { | ||
281 | mc.MaxReqSize = newInt(maxInt) | ||
282 | } else { | ||
283 | mc.MaxReqSize = newInt(int(*m.MaxRequestMessageBytes)) | ||
284 | } | ||
285 | } | ||
286 | if m.MaxResponseMessageBytes != nil { | ||
287 | if *m.MaxResponseMessageBytes > int64(maxInt) { | ||
288 | mc.MaxRespSize = newInt(maxInt) | ||
289 | } else { | ||
290 | mc.MaxRespSize = newInt(int(*m.MaxResponseMessageBytes)) | ||
291 | } | ||
292 | } | ||
293 | for _, n := range *m.Name { | ||
294 | if path, valid := n.generatePath(); valid { | ||
295 | sc.Methods[path] = mc | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | |||
300 | if sc.retryThrottling != nil { | ||
301 | if sc.retryThrottling.MaxTokens <= 0 || | ||
302 | sc.retryThrottling.MaxTokens >= 1000 || | ||
303 | sc.retryThrottling.TokenRatio <= 0 { | ||
304 | // Illegal throttling config; disable throttling. | ||
305 | sc.retryThrottling = nil | ||
306 | } | ||
307 | } | ||
308 | return sc, nil | ||
309 | } | ||
310 | |||
311 | func convertRetryPolicy(jrp *jsonRetryPolicy) (p *retryPolicy, err error) { | ||
312 | if jrp == nil { | ||
313 | return nil, nil | ||
314 | } | ||
315 | ib, err := parseDuration(&jrp.InitialBackoff) | ||
316 | if err != nil { | ||
317 | return nil, err | ||
318 | } | ||
319 | mb, err := parseDuration(&jrp.MaxBackoff) | ||
320 | if err != nil { | ||
321 | return nil, err | ||
322 | } | ||
323 | |||
324 | if jrp.MaxAttempts <= 1 || | ||
325 | *ib <= 0 || | ||
326 | *mb <= 0 || | ||
327 | jrp.BackoffMultiplier <= 0 || | ||
328 | len(jrp.RetryableStatusCodes) == 0 { | ||
329 | grpclog.Warningf("grpc: ignoring retry policy %v due to illegal configuration", jrp) | ||
330 | return nil, nil | ||
331 | } | ||
332 | |||
333 | rp := &retryPolicy{ | ||
334 | maxAttempts: jrp.MaxAttempts, | ||
335 | initialBackoff: *ib, | ||
336 | maxBackoff: *mb, | ||
337 | backoffMultiplier: jrp.BackoffMultiplier, | ||
338 | retryableStatusCodes: make(map[codes.Code]bool), | ||
339 | } | ||
340 | if rp.maxAttempts > 5 { | ||
341 | // TODO(retry): Make the max maxAttempts configurable. | ||
342 | rp.maxAttempts = 5 | ||
343 | } | ||
344 | for _, code := range jrp.RetryableStatusCodes { | ||
345 | rp.retryableStatusCodes[code] = true | ||
346 | } | ||
347 | return rp, nil | ||
348 | } | ||
349 | |||
350 | func min(a, b *int) *int { | ||
351 | if *a < *b { | ||
352 | return a | ||
353 | } | ||
354 | return b | ||
355 | } | ||
356 | |||
357 | func getMaxSize(mcMax, doptMax *int, defaultVal int) *int { | ||
358 | if mcMax == nil && doptMax == nil { | ||
359 | return &defaultVal | ||
360 | } | ||
361 | if mcMax != nil && doptMax != nil { | ||
362 | return min(mcMax, doptMax) | ||
363 | } | ||
364 | if mcMax != nil { | ||
365 | return mcMax | ||
366 | } | ||
367 | return doptMax | ||
368 | } | ||
369 | |||
370 | func newInt(b int) *int { | ||
371 | return &b | ||
372 | } | ||
diff --git a/vendor/google.golang.org/grpc/stats/handlers.go b/vendor/google.golang.org/grpc/stats/handlers.go index 05b384c..dc03731 100644 --- a/vendor/google.golang.org/grpc/stats/handlers.go +++ b/vendor/google.golang.org/grpc/stats/handlers.go | |||
@@ -19,9 +19,8 @@ | |||
19 | package stats | 19 | package stats |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "context" | ||
22 | "net" | 23 | "net" |
23 | |||
24 | "golang.org/x/net/context" | ||
25 | ) | 24 | ) |
26 | 25 | ||
27 | // ConnTagInfo defines the relevant information needed by connection context tagger. | 26 | // ConnTagInfo defines the relevant information needed by connection context tagger. |
diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index 338a3a7..84f77da 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go | |||
@@ -16,12 +16,15 @@ | |||
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | //go:generate protoc --go_out=plugins=grpc:. grpc_testing/test.proto | ||
20 | |||
19 | // Package stats is for collecting and reporting various network and RPC stats. | 21 | // Package stats is for collecting and reporting various network and RPC stats. |
20 | // This package is for monitoring purpose only. All fields are read-only. | 22 | // This package is for monitoring purpose only. All fields are read-only. |
21 | // All APIs are experimental. | 23 | // All APIs are experimental. |
22 | package stats // import "google.golang.org/grpc/stats" | 24 | package stats // import "google.golang.org/grpc/stats" |
23 | 25 | ||
24 | import ( | 26 | import ( |
27 | "context" | ||
25 | "net" | 28 | "net" |
26 | "time" | 29 | "time" |
27 | ) | 30 | ) |
@@ -131,8 +134,6 @@ func (s *OutPayload) isRPCStats() {} | |||
131 | type OutHeader struct { | 134 | type OutHeader struct { |
132 | // Client is true if this OutHeader is from client side. | 135 | // Client is true if this OutHeader is from client side. |
133 | Client bool | 136 | Client bool |
134 | // WireLength is the wire length of header. | ||
135 | WireLength int | ||
136 | 137 | ||
137 | // The following fields are valid only if Client is true. | 138 | // The following fields are valid only if Client is true. |
138 | // FullMethod is the full RPC method string, i.e., /package.service/method. | 139 | // FullMethod is the full RPC method string, i.e., /package.service/method. |
@@ -167,6 +168,8 @@ func (s *OutTrailer) isRPCStats() {} | |||
167 | type End struct { | 168 | type End struct { |
168 | // Client is true if this End is from client side. | 169 | // Client is true if this End is from client side. |
169 | Client bool | 170 | Client bool |
171 | // BeginTime is the time when the RPC began. | ||
172 | BeginTime time.Time | ||
170 | // EndTime is the time when the RPC ends. | 173 | // EndTime is the time when the RPC ends. |
171 | EndTime time.Time | 174 | EndTime time.Time |
172 | // Error is the error the RPC ended with. It is an error generated from | 175 | // Error is the error the RPC ended with. It is an error generated from |
@@ -208,3 +211,85 @@ type ConnEnd struct { | |||
208 | func (s *ConnEnd) IsClient() bool { return s.Client } | 211 | func (s *ConnEnd) IsClient() bool { return s.Client } |
209 | 212 | ||
210 | func (s *ConnEnd) isConnStats() {} | 213 | func (s *ConnEnd) isConnStats() {} |
214 | |||
215 | type incomingTagsKey struct{} | ||
216 | type outgoingTagsKey struct{} | ||
217 | |||
218 | // SetTags attaches stats tagging data to the context, which will be sent in | ||
219 | // the outgoing RPC with the header grpc-tags-bin. Subsequent calls to | ||
220 | // SetTags will overwrite the values from earlier calls. | ||
221 | // | ||
222 | // NOTE: this is provided only for backward compatibility with existing clients | ||
223 | // and will likely be removed in an upcoming release. New uses should transmit | ||
224 | // this type of data using metadata with a different, non-reserved (i.e. does | ||
225 | // not begin with "grpc-") header name. | ||
226 | func SetTags(ctx context.Context, b []byte) context.Context { | ||
227 | return context.WithValue(ctx, outgoingTagsKey{}, b) | ||
228 | } | ||
229 | |||
230 | // Tags returns the tags from the context for the inbound RPC. | ||
231 | // | ||
232 | // NOTE: this is provided only for backward compatibility with existing clients | ||
233 | // and will likely be removed in an upcoming release. New uses should transmit | ||
234 | // this type of data using metadata with a different, non-reserved (i.e. does | ||
235 | // not begin with "grpc-") header name. | ||
236 | func Tags(ctx context.Context) []byte { | ||
237 | b, _ := ctx.Value(incomingTagsKey{}).([]byte) | ||
238 | return b | ||
239 | } | ||
240 | |||
241 | // SetIncomingTags attaches stats tagging data to the context, to be read by | ||
242 | // the application (not sent in outgoing RPCs). | ||
243 | // | ||
244 | // This is intended for gRPC-internal use ONLY. | ||
245 | func SetIncomingTags(ctx context.Context, b []byte) context.Context { | ||
246 | return context.WithValue(ctx, incomingTagsKey{}, b) | ||
247 | } | ||
248 | |||
249 | // OutgoingTags returns the tags from the context for the outbound RPC. | ||
250 | // | ||
251 | // This is intended for gRPC-internal use ONLY. | ||
252 | func OutgoingTags(ctx context.Context) []byte { | ||
253 | b, _ := ctx.Value(outgoingTagsKey{}).([]byte) | ||
254 | return b | ||
255 | } | ||
256 | |||
257 | type incomingTraceKey struct{} | ||
258 | type outgoingTraceKey struct{} | ||
259 | |||
260 | // SetTrace attaches stats tagging data to the context, which will be sent in | ||
261 | // the outgoing RPC with the header grpc-trace-bin. Subsequent calls to | ||
262 | // SetTrace will overwrite the values from earlier calls. | ||
263 | // | ||
264 | // NOTE: this is provided only for backward compatibility with existing clients | ||
265 | // and will likely be removed in an upcoming release. New uses should transmit | ||
266 | // this type of data using metadata with a different, non-reserved (i.e. does | ||
267 | // not begin with "grpc-") header name. | ||
268 | func SetTrace(ctx context.Context, b []byte) context.Context { | ||
269 | return context.WithValue(ctx, outgoingTraceKey{}, b) | ||
270 | } | ||
271 | |||
272 | // Trace returns the trace from the context for the inbound RPC. | ||
273 | // | ||
274 | // NOTE: this is provided only for backward compatibility with existing clients | ||
275 | // and will likely be removed in an upcoming release. New uses should transmit | ||
276 | // this type of data using metadata with a different, non-reserved (i.e. does | ||
277 | // not begin with "grpc-") header name. | ||
278 | func Trace(ctx context.Context) []byte { | ||
279 | b, _ := ctx.Value(incomingTraceKey{}).([]byte) | ||
280 | return b | ||
281 | } | ||
282 | |||
283 | // SetIncomingTrace attaches stats tagging data to the context, to be read by | ||
284 | // the application (not sent in outgoing RPCs). It is intended for | ||
285 | // gRPC-internal use. | ||
286 | func SetIncomingTrace(ctx context.Context, b []byte) context.Context { | ||
287 | return context.WithValue(ctx, incomingTraceKey{}, b) | ||
288 | } | ||
289 | |||
290 | // OutgoingTrace returns the trace from the context for the outbound RPC. It is | ||
291 | // intended for gRPC-internal use. | ||
292 | func OutgoingTrace(ctx context.Context) []byte { | ||
293 | b, _ := ctx.Value(outgoingTraceKey{}).([]byte) | ||
294 | return b | ||
295 | } | ||
diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go index 871dc4b..ed36681 100644 --- a/vendor/google.golang.org/grpc/status/status.go +++ b/vendor/google.golang.org/grpc/status/status.go | |||
@@ -28,6 +28,7 @@ | |||
28 | package status | 28 | package status |
29 | 29 | ||
30 | import ( | 30 | import ( |
31 | "context" | ||
31 | "errors" | 32 | "errors" |
32 | "fmt" | 33 | "fmt" |
33 | 34 | ||
@@ -46,7 +47,7 @@ func (se *statusError) Error() string { | |||
46 | return fmt.Sprintf("rpc error: code = %s desc = %s", codes.Code(p.GetCode()), p.GetMessage()) | 47 | return fmt.Sprintf("rpc error: code = %s desc = %s", codes.Code(p.GetCode()), p.GetMessage()) |
47 | } | 48 | } |
48 | 49 | ||
49 | func (se *statusError) status() *Status { | 50 | func (se *statusError) GRPCStatus() *Status { |
50 | return &Status{s: (*spb.Status)(se)} | 51 | return &Status{s: (*spb.Status)(se)} |
51 | } | 52 | } |
52 | 53 | ||
@@ -120,15 +121,25 @@ func FromProto(s *spb.Status) *Status { | |||
120 | } | 121 | } |
121 | 122 | ||
122 | // FromError returns a Status representing err if it was produced from this | 123 | // FromError returns a Status representing err if it was produced from this |
123 | // package, otherwise it returns nil, false. | 124 | // package or has a method `GRPCStatus() *Status`. Otherwise, ok is false and a |
125 | // Status is returned with codes.Unknown and the original error message. | ||
124 | func FromError(err error) (s *Status, ok bool) { | 126 | func FromError(err error) (s *Status, ok bool) { |
125 | if err == nil { | 127 | if err == nil { |
126 | return &Status{s: &spb.Status{Code: int32(codes.OK)}}, true | 128 | return &Status{s: &spb.Status{Code: int32(codes.OK)}}, true |
127 | } | 129 | } |
128 | if s, ok := err.(*statusError); ok { | 130 | if se, ok := err.(interface { |
129 | return s.status(), true | 131 | GRPCStatus() *Status |
132 | }); ok { | ||
133 | return se.GRPCStatus(), true | ||
130 | } | 134 | } |
131 | return nil, false | 135 | return New(codes.Unknown, err.Error()), false |
136 | } | ||
137 | |||
138 | // Convert is a convenience function which removes the need to handle the | ||
139 | // boolean return value from FromError. | ||
140 | func Convert(err error) *Status { | ||
141 | s, _ := FromError(err) | ||
142 | return s | ||
132 | } | 143 | } |
133 | 144 | ||
134 | // WithDetails returns a new status with the provided details messages appended to the status. | 145 | // WithDetails returns a new status with the provided details messages appended to the status. |
@@ -166,3 +177,34 @@ func (s *Status) Details() []interface{} { | |||
166 | } | 177 | } |
167 | return details | 178 | return details |
168 | } | 179 | } |
180 | |||
181 | // Code returns the Code of the error if it is a Status error, codes.OK if err | ||
182 | // is nil, or codes.Unknown otherwise. | ||
183 | func Code(err error) codes.Code { | ||
184 | // Don't use FromError to avoid allocation of OK status. | ||
185 | if err == nil { | ||
186 | return codes.OK | ||
187 | } | ||
188 | if se, ok := err.(interface { | ||
189 | GRPCStatus() *Status | ||
190 | }); ok { | ||
191 | return se.GRPCStatus().Code() | ||
192 | } | ||
193 | return codes.Unknown | ||
194 | } | ||
195 | |||
196 | // FromContextError converts a context error into a Status. It returns a | ||
197 | // Status with codes.OK if err is nil, or a Status with codes.Unknown if err is | ||
198 | // non-nil and not a context error. | ||
199 | func FromContextError(err error) *Status { | ||
200 | switch err { | ||
201 | case nil: | ||
202 | return New(codes.OK, "") | ||
203 | case context.DeadlineExceeded: | ||
204 | return New(codes.DeadlineExceeded, err.Error()) | ||
205 | case context.Canceled: | ||
206 | return New(codes.Canceled, err.Error()) | ||
207 | default: | ||
208 | return New(codes.Unknown, err.Error()) | ||
209 | } | ||
210 | } | ||
diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index 1c621ba..d06279a 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go | |||
@@ -19,24 +19,35 @@ | |||
19 | package grpc | 19 | package grpc |
20 | 20 | ||
21 | import ( | 21 | import ( |
22 | "bytes" | 22 | "context" |
23 | "errors" | 23 | "errors" |
24 | "io" | 24 | "io" |
25 | "math" | ||
26 | "strconv" | ||
25 | "sync" | 27 | "sync" |
26 | "time" | 28 | "time" |
27 | 29 | ||
28 | "golang.org/x/net/context" | ||
29 | "golang.org/x/net/trace" | 30 | "golang.org/x/net/trace" |
31 | "google.golang.org/grpc/balancer" | ||
30 | "google.golang.org/grpc/codes" | 32 | "google.golang.org/grpc/codes" |
33 | "google.golang.org/grpc/connectivity" | ||
34 | "google.golang.org/grpc/encoding" | ||
35 | "google.golang.org/grpc/grpclog" | ||
36 | "google.golang.org/grpc/internal/binarylog" | ||
37 | "google.golang.org/grpc/internal/channelz" | ||
38 | "google.golang.org/grpc/internal/grpcrand" | ||
39 | "google.golang.org/grpc/internal/transport" | ||
31 | "google.golang.org/grpc/metadata" | 40 | "google.golang.org/grpc/metadata" |
32 | "google.golang.org/grpc/peer" | 41 | "google.golang.org/grpc/peer" |
33 | "google.golang.org/grpc/stats" | 42 | "google.golang.org/grpc/stats" |
34 | "google.golang.org/grpc/status" | 43 | "google.golang.org/grpc/status" |
35 | "google.golang.org/grpc/transport" | ||
36 | ) | 44 | ) |
37 | 45 | ||
38 | // StreamHandler defines the handler called by gRPC server to complete the | 46 | // StreamHandler defines the handler called by gRPC server to complete the |
39 | // execution of a streaming RPC. | 47 | // execution of a streaming RPC. If a StreamHandler returns an error, it |
48 | // should be produced by the status package, or else gRPC will use | ||
49 | // codes.Unknown as the status code and err.Error() as the status message | ||
50 | // of the RPC. | ||
40 | type StreamHandler func(srv interface{}, stream ServerStream) error | 51 | type StreamHandler func(srv interface{}, stream ServerStream) error |
41 | 52 | ||
42 | // StreamDesc represents a streaming RPC service's method specification. | 53 | // StreamDesc represents a streaming RPC service's method specification. |
@@ -50,30 +61,21 @@ type StreamDesc struct { | |||
50 | } | 61 | } |
51 | 62 | ||
52 | // Stream defines the common interface a client or server stream has to satisfy. | 63 | // Stream defines the common interface a client or server stream has to satisfy. |
64 | // | ||
65 | // Deprecated: See ClientStream and ServerStream documentation instead. | ||
53 | type Stream interface { | 66 | type Stream interface { |
54 | // Context returns the context for this stream. | 67 | // Deprecated: See ClientStream and ServerStream documentation instead. |
55 | Context() context.Context | 68 | Context() context.Context |
56 | // SendMsg blocks until it sends m, the stream is done or the stream | 69 | // Deprecated: See ClientStream and ServerStream documentation instead. |
57 | // breaks. | ||
58 | // On error, it aborts the stream and returns an RPC status on client | ||
59 | // side. On server side, it simply returns the error to the caller. | ||
60 | // SendMsg is called by generated code. Also Users can call SendMsg | ||
61 | // directly when it is really needed in their use cases. | ||
62 | // It's safe to have a goroutine calling SendMsg and another goroutine calling | ||
63 | // recvMsg on the same stream at the same time. | ||
64 | // But it is not safe to call SendMsg on the same stream in different goroutines. | ||
65 | SendMsg(m interface{}) error | 70 | SendMsg(m interface{}) error |
66 | // RecvMsg blocks until it receives a message or the stream is | 71 | // Deprecated: See ClientStream and ServerStream documentation instead. |
67 | // done. On client side, it returns io.EOF when the stream is done. On | ||
68 | // any other error, it aborts the stream and returns an RPC status. On | ||
69 | // server side, it simply returns the error to the caller. | ||
70 | // It's safe to have a goroutine calling SendMsg and another goroutine calling | ||
71 | // recvMsg on the same stream at the same time. | ||
72 | // But it is not safe to call RecvMsg on the same stream in different goroutines. | ||
73 | RecvMsg(m interface{}) error | 72 | RecvMsg(m interface{}) error |
74 | } | 73 | } |
75 | 74 | ||
76 | // ClientStream defines the interface a client stream has to satisfy. | 75 | // ClientStream defines the client-side behavior of a streaming RPC. |
76 | // | ||
77 | // All errors returned from ClientStream methods are compatible with the | ||
78 | // status package. | ||
77 | type ClientStream interface { | 79 | type ClientStream interface { |
78 | // Header returns the header metadata received from the server if there | 80 | // Header returns the header metadata received from the server if there |
79 | // is any. It blocks if the metadata is not ready to read. | 81 | // is any. It blocks if the metadata is not ready to read. |
@@ -83,62 +85,147 @@ type ClientStream interface { | |||
83 | // stream.Recv has returned a non-nil error (including io.EOF). | 85 | // stream.Recv has returned a non-nil error (including io.EOF). |
84 | Trailer() metadata.MD | 86 | Trailer() metadata.MD |
85 | // CloseSend closes the send direction of the stream. It closes the stream | 87 | // CloseSend closes the send direction of the stream. It closes the stream |
86 | // when non-nil error is met. | 88 | // when non-nil error is met. It is also not safe to call CloseSend |
89 | // concurrently with SendMsg. | ||
87 | CloseSend() error | 90 | CloseSend() error |
88 | // Stream.SendMsg() may return a non-nil error when something wrong happens sending | 91 | // Context returns the context for this stream. |
89 | // the request. The returned error indicates the status of this sending, not the final | 92 | // |
90 | // status of the RPC. | 93 | // It should not be called until after Header or RecvMsg has returned. Once |
91 | // Always call Stream.RecvMsg() to get the final status if you care about the status of | 94 | // called, subsequent client-side retries are disabled. |
92 | // the RPC. | 95 | Context() context.Context |
93 | Stream | 96 | // SendMsg is generally called by generated code. On error, SendMsg aborts |
97 | // the stream. If the error was generated by the client, the status is | ||
98 | // returned directly; otherwise, io.EOF is returned and the status of | ||
99 | // the stream may be discovered using RecvMsg. | ||
100 | // | ||
101 | // SendMsg blocks until: | ||
102 | // - There is sufficient flow control to schedule m with the transport, or | ||
103 | // - The stream is done, or | ||
104 | // - The stream breaks. | ||
105 | // | ||
106 | // SendMsg does not wait until the message is received by the server. An | ||
107 | // untimely stream closure may result in lost messages. To ensure delivery, | ||
108 | // users should ensure the RPC completed successfully using RecvMsg. | ||
109 | // | ||
110 | // It is safe to have a goroutine calling SendMsg and another goroutine | ||
111 | // calling RecvMsg on the same stream at the same time, but it is not safe | ||
112 | // to call SendMsg on the same stream in different goroutines. It is also | ||
113 | // not safe to call CloseSend concurrently with SendMsg. | ||
114 | SendMsg(m interface{}) error | ||
115 | // RecvMsg blocks until it receives a message into m or the stream is | ||
116 | // done. It returns io.EOF when the stream completes successfully. On | ||
117 | // any other error, the stream is aborted and the error contains the RPC | ||
118 | // status. | ||
119 | // | ||
120 | // It is safe to have a goroutine calling SendMsg and another goroutine | ||
121 | // calling RecvMsg on the same stream at the same time, but it is not | ||
122 | // safe to call RecvMsg on the same stream in different goroutines. | ||
123 | RecvMsg(m interface{}) error | ||
94 | } | 124 | } |
95 | 125 | ||
96 | // NewClientStream creates a new Stream for the client side. This is called | 126 | // NewStream creates a new Stream for the client side. This is typically |
97 | // by generated code. | 127 | // called by generated code. ctx is used for the lifetime of the stream. |
98 | func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { | 128 | // |
129 | // To ensure resources are not leaked due to the stream returned, one of the following | ||
130 | // actions must be performed: | ||
131 | // | ||
132 | // 1. Call Close on the ClientConn. | ||
133 | // 2. Cancel the context provided. | ||
134 | // 3. Call RecvMsg until a non-nil error is returned. A protobuf-generated | ||
135 | // client-streaming RPC, for instance, might use the helper function | ||
136 | // CloseAndRecv (note that CloseSend does not Recv, therefore is not | ||
137 | // guaranteed to release all resources). | ||
138 | // 4. Receive a non-nil, non-io.EOF error from Header or SendMsg. | ||
139 | // | ||
140 | // If none of the above happen, a goroutine and a context will be leaked, and grpc | ||
141 | // will not call the optionally-configured stats handler with a stats.End message. | ||
142 | func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { | ||
143 | // allow interceptor to see all applicable call options, which means those | ||
144 | // configured as defaults from dial option as well as per-call options | ||
145 | opts = combine(cc.dopts.callOptions, opts) | ||
146 | |||
99 | if cc.dopts.streamInt != nil { | 147 | if cc.dopts.streamInt != nil { |
100 | return cc.dopts.streamInt(ctx, desc, cc, method, newClientStream, opts...) | 148 | return cc.dopts.streamInt(ctx, desc, cc, method, newClientStream, opts...) |
101 | } | 149 | } |
102 | return newClientStream(ctx, desc, cc, method, opts...) | 150 | return newClientStream(ctx, desc, cc, method, opts...) |
103 | } | 151 | } |
104 | 152 | ||
153 | // NewClientStream is a wrapper for ClientConn.NewStream. | ||
154 | func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { | ||
155 | return cc.NewStream(ctx, desc, method, opts...) | ||
156 | } | ||
157 | |||
105 | func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { | 158 | func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { |
106 | var ( | 159 | if channelz.IsOn() { |
107 | t transport.ClientTransport | 160 | cc.incrCallsStarted() |
108 | s *transport.Stream | 161 | defer func() { |
109 | put func() | 162 | if err != nil { |
110 | cancel context.CancelFunc | 163 | cc.incrCallsFailed() |
111 | ) | 164 | } |
112 | c := defaultCallInfo | 165 | }() |
166 | } | ||
167 | c := defaultCallInfo() | ||
168 | // Provide an opportunity for the first RPC to see the first service config | ||
169 | // provided by the resolver. | ||
170 | if err := cc.waitForResolvedAddrs(ctx); err != nil { | ||
171 | return nil, err | ||
172 | } | ||
113 | mc := cc.GetMethodConfig(method) | 173 | mc := cc.GetMethodConfig(method) |
114 | if mc.WaitForReady != nil { | 174 | if mc.WaitForReady != nil { |
115 | c.failFast = !*mc.WaitForReady | 175 | c.failFast = !*mc.WaitForReady |
116 | } | 176 | } |
117 | 177 | ||
118 | if mc.Timeout != nil { | 178 | // Possible context leak: |
179 | // The cancel function for the child context we create will only be called | ||
180 | // when RecvMsg returns a non-nil error, if the ClientConn is closed, or if | ||
181 | // an error is generated by SendMsg. | ||
182 | // https://github.com/grpc/grpc-go/issues/1818. | ||
183 | var cancel context.CancelFunc | ||
184 | if mc.Timeout != nil && *mc.Timeout >= 0 { | ||
119 | ctx, cancel = context.WithTimeout(ctx, *mc.Timeout) | 185 | ctx, cancel = context.WithTimeout(ctx, *mc.Timeout) |
186 | } else { | ||
187 | ctx, cancel = context.WithCancel(ctx) | ||
120 | } | 188 | } |
189 | defer func() { | ||
190 | if err != nil { | ||
191 | cancel() | ||
192 | } | ||
193 | }() | ||
121 | 194 | ||
122 | opts = append(cc.dopts.callOptions, opts...) | ||
123 | for _, o := range opts { | 195 | for _, o := range opts { |
124 | if err := o.before(&c); err != nil { | 196 | if err := o.before(c); err != nil { |
125 | return nil, toRPCErr(err) | 197 | return nil, toRPCErr(err) |
126 | } | 198 | } |
127 | } | 199 | } |
128 | c.maxSendMessageSize = getMaxSize(mc.MaxReqSize, c.maxSendMessageSize, defaultClientMaxSendMessageSize) | 200 | c.maxSendMessageSize = getMaxSize(mc.MaxReqSize, c.maxSendMessageSize, defaultClientMaxSendMessageSize) |
129 | c.maxReceiveMessageSize = getMaxSize(mc.MaxRespSize, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) | 201 | c.maxReceiveMessageSize = getMaxSize(mc.MaxRespSize, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) |
202 | if err := setCallInfoCodec(c); err != nil { | ||
203 | return nil, err | ||
204 | } | ||
130 | 205 | ||
131 | callHdr := &transport.CallHdr{ | 206 | callHdr := &transport.CallHdr{ |
132 | Host: cc.authority, | 207 | Host: cc.authority, |
133 | Method: method, | 208 | Method: method, |
134 | // If it's not client streaming, we should already have the request to be sent, | 209 | ContentSubtype: c.contentSubtype, |
135 | // so we don't flush the header. | 210 | } |
136 | // If it's client streaming, the user may never send a request or send it any | 211 | |
137 | // time soon, so we ask the transport to flush the header. | 212 | // Set our outgoing compression according to the UseCompressor CallOption, if |
138 | Flush: desc.ClientStreams, | 213 | // set. In that case, also find the compressor from the encoding package. |
139 | } | 214 | // Otherwise, use the compressor configured by the WithCompressor DialOption, |
140 | if cc.dopts.cp != nil { | 215 | // if set. |
216 | var cp Compressor | ||
217 | var comp encoding.Compressor | ||
218 | if ct := c.compressorType; ct != "" { | ||
219 | callHdr.SendCompress = ct | ||
220 | if ct != encoding.Identity { | ||
221 | comp = encoding.GetCompressor(ct) | ||
222 | if comp == nil { | ||
223 | return nil, status.Errorf(codes.Internal, "grpc: Compressor is not installed for requested grpc-encoding %q", ct) | ||
224 | } | ||
225 | } | ||
226 | } else if cc.dopts.cp != nil { | ||
141 | callHdr.SendCompress = cc.dopts.cp.Type() | 227 | callHdr.SendCompress = cc.dopts.cp.Type() |
228 | cp = cc.dopts.cp | ||
142 | } | 229 | } |
143 | if c.creds != nil { | 230 | if c.creds != nil { |
144 | callHdr.Creds = c.creds | 231 | callHdr.Creds = c.creds |
@@ -152,380 +239,1019 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth | |||
152 | } | 239 | } |
153 | trInfo.tr.LazyLog(&trInfo.firstLine, false) | 240 | trInfo.tr.LazyLog(&trInfo.firstLine, false) |
154 | ctx = trace.NewContext(ctx, trInfo.tr) | 241 | ctx = trace.NewContext(ctx, trInfo.tr) |
155 | defer func() { | ||
156 | if err != nil { | ||
157 | // Need to call tr.finish() if error is returned. | ||
158 | // Because tr will not be returned to caller. | ||
159 | trInfo.tr.LazyPrintf("RPC: [%v]", err) | ||
160 | trInfo.tr.SetError() | ||
161 | trInfo.tr.Finish() | ||
162 | } | ||
163 | }() | ||
164 | } | 242 | } |
165 | ctx = newContextWithRPCInfo(ctx) | 243 | ctx = newContextWithRPCInfo(ctx, c.failFast) |
166 | sh := cc.dopts.copts.StatsHandler | 244 | sh := cc.dopts.copts.StatsHandler |
245 | var beginTime time.Time | ||
167 | if sh != nil { | 246 | if sh != nil { |
168 | ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast}) | 247 | ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast}) |
248 | beginTime = time.Now() | ||
169 | begin := &stats.Begin{ | 249 | begin := &stats.Begin{ |
170 | Client: true, | 250 | Client: true, |
171 | BeginTime: time.Now(), | 251 | BeginTime: beginTime, |
172 | FailFast: c.failFast, | 252 | FailFast: c.failFast, |
173 | } | 253 | } |
174 | sh.HandleRPC(ctx, begin) | 254 | sh.HandleRPC(ctx, begin) |
175 | defer func() { | ||
176 | if err != nil { | ||
177 | // Only handle end stats if err != nil. | ||
178 | end := &stats.End{ | ||
179 | Client: true, | ||
180 | Error: err, | ||
181 | } | ||
182 | sh.HandleRPC(ctx, end) | ||
183 | } | ||
184 | }() | ||
185 | } | 255 | } |
186 | gopts := BalancerGetOptions{ | 256 | |
187 | BlockingWait: !c.failFast, | 257 | cs := &clientStream{ |
258 | callHdr: callHdr, | ||
259 | ctx: ctx, | ||
260 | methodConfig: &mc, | ||
261 | opts: opts, | ||
262 | callInfo: c, | ||
263 | cc: cc, | ||
264 | desc: desc, | ||
265 | codec: c.codec, | ||
266 | cp: cp, | ||
267 | comp: comp, | ||
268 | cancel: cancel, | ||
269 | beginTime: beginTime, | ||
270 | firstAttempt: true, | ||
271 | } | ||
272 | if !cc.dopts.disableRetry { | ||
273 | cs.retryThrottler = cc.retryThrottler.Load().(*retryThrottler) | ||
188 | } | 274 | } |
189 | for { | 275 | cs.binlog = binarylog.GetMethodLogger(method) |
190 | t, put, err = cc.getTransport(ctx, gopts) | ||
191 | if err != nil { | ||
192 | // TODO(zhaoq): Probably revisit the error handling. | ||
193 | if _, ok := status.FromError(err); ok { | ||
194 | return nil, err | ||
195 | } | ||
196 | if err == errConnClosing || err == errConnUnavailable { | ||
197 | if c.failFast { | ||
198 | return nil, Errorf(codes.Unavailable, "%v", err) | ||
199 | } | ||
200 | continue | ||
201 | } | ||
202 | // All the other errors are treated as Internal errors. | ||
203 | return nil, Errorf(codes.Internal, "%v", err) | ||
204 | } | ||
205 | 276 | ||
206 | s, err = t.NewStream(ctx, callHdr) | 277 | cs.callInfo.stream = cs |
207 | if err != nil { | 278 | // Only this initial attempt has stats/tracing. |
208 | if _, ok := err.(transport.ConnectionError); ok && put != nil { | 279 | // TODO(dfawley): move to newAttempt when per-attempt stats are implemented. |
209 | // If error is connection error, transport was sending data on wire, | 280 | if err := cs.newAttemptLocked(sh, trInfo); err != nil { |
210 | // and we are not sure if anything has been sent on wire. | 281 | cs.finish(err) |
211 | // If error is not connection error, we are sure nothing has been sent. | 282 | return nil, err |
212 | updateRPCInfoInContext(ctx, rpcInfo{bytesSent: true, bytesReceived: false}) | 283 | } |
213 | } | 284 | |
214 | if put != nil { | 285 | op := func(a *csAttempt) error { return a.newStream() } |
215 | put() | 286 | if err := cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }); err != nil { |
216 | put = nil | 287 | cs.finish(err) |
217 | } | 288 | return nil, err |
218 | if _, ok := err.(transport.ConnectionError); (ok || err == transport.ErrStreamDrain) && !c.failFast { | 289 | } |
219 | continue | 290 | |
291 | if cs.binlog != nil { | ||
292 | md, _ := metadata.FromOutgoingContext(ctx) | ||
293 | logEntry := &binarylog.ClientHeader{ | ||
294 | OnClientSide: true, | ||
295 | Header: md, | ||
296 | MethodName: method, | ||
297 | Authority: cs.cc.authority, | ||
298 | } | ||
299 | if deadline, ok := ctx.Deadline(); ok { | ||
300 | logEntry.Timeout = deadline.Sub(time.Now()) | ||
301 | if logEntry.Timeout < 0 { | ||
302 | logEntry.Timeout = 0 | ||
220 | } | 303 | } |
221 | return nil, toRPCErr(err) | ||
222 | } | 304 | } |
223 | break | 305 | cs.binlog.Log(logEntry) |
224 | } | 306 | } |
225 | // Set callInfo.peer object from stream's context. | 307 | |
226 | if peer, ok := peer.FromContext(s.Context()); ok { | 308 | if desc != unaryStreamDesc { |
227 | c.peer = peer | 309 | // Listen on cc and stream contexts to cleanup when the user closes the |
310 | // ClientConn or cancels the stream context. In all other cases, an error | ||
311 | // should already be injected into the recv buffer by the transport, which | ||
312 | // the client will eventually receive, and then we will cancel the stream's | ||
313 | // context in clientStream.finish. | ||
314 | go func() { | ||
315 | select { | ||
316 | case <-cc.ctx.Done(): | ||
317 | cs.finish(ErrClientConnClosing) | ||
318 | case <-ctx.Done(): | ||
319 | cs.finish(toRPCErr(ctx.Err())) | ||
320 | } | ||
321 | }() | ||
228 | } | 322 | } |
229 | cs := &clientStream{ | ||
230 | opts: opts, | ||
231 | c: c, | ||
232 | desc: desc, | ||
233 | codec: cc.dopts.codec, | ||
234 | cp: cc.dopts.cp, | ||
235 | dc: cc.dopts.dc, | ||
236 | cancel: cancel, | ||
237 | |||
238 | put: put, | ||
239 | t: t, | ||
240 | s: s, | ||
241 | p: &parser{r: s}, | ||
242 | |||
243 | tracing: EnableTracing, | ||
244 | trInfo: trInfo, | ||
245 | |||
246 | statsCtx: ctx, | ||
247 | statsHandler: cc.dopts.copts.StatsHandler, | ||
248 | } | ||
249 | if cc.dopts.cp != nil { | ||
250 | cs.cbuf = new(bytes.Buffer) | ||
251 | } | ||
252 | // Listen on ctx.Done() to detect cancellation and s.Done() to detect normal termination | ||
253 | // when there is no pending I/O operations on this stream. | ||
254 | go func() { | ||
255 | select { | ||
256 | case <-t.Error(): | ||
257 | // Incur transport error, simply exit. | ||
258 | case <-cc.ctx.Done(): | ||
259 | cs.finish(ErrClientConnClosing) | ||
260 | cs.closeTransportStream(ErrClientConnClosing) | ||
261 | case <-s.Done(): | ||
262 | // TODO: The trace of the RPC is terminated here when there is no pending | ||
263 | // I/O, which is probably not the optimal solution. | ||
264 | cs.finish(s.Status().Err()) | ||
265 | cs.closeTransportStream(nil) | ||
266 | case <-s.GoAway(): | ||
267 | cs.finish(errConnDrain) | ||
268 | cs.closeTransportStream(errConnDrain) | ||
269 | case <-s.Context().Done(): | ||
270 | err := s.Context().Err() | ||
271 | cs.finish(err) | ||
272 | cs.closeTransportStream(transport.ContextErr(err)) | ||
273 | } | ||
274 | }() | ||
275 | return cs, nil | 323 | return cs, nil |
276 | } | 324 | } |
277 | 325 | ||
326 | func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo traceInfo) error { | ||
327 | cs.attempt = &csAttempt{ | ||
328 | cs: cs, | ||
329 | dc: cs.cc.dopts.dc, | ||
330 | statsHandler: sh, | ||
331 | trInfo: trInfo, | ||
332 | } | ||
333 | |||
334 | if err := cs.ctx.Err(); err != nil { | ||
335 | return toRPCErr(err) | ||
336 | } | ||
337 | t, done, err := cs.cc.getTransport(cs.ctx, cs.callInfo.failFast, cs.callHdr.Method) | ||
338 | if err != nil { | ||
339 | return err | ||
340 | } | ||
341 | cs.attempt.t = t | ||
342 | cs.attempt.done = done | ||
343 | return nil | ||
344 | } | ||
345 | |||
346 | func (a *csAttempt) newStream() error { | ||
347 | cs := a.cs | ||
348 | cs.callHdr.PreviousAttempts = cs.numRetries | ||
349 | s, err := a.t.NewStream(cs.ctx, cs.callHdr) | ||
350 | if err != nil { | ||
351 | return toRPCErr(err) | ||
352 | } | ||
353 | cs.attempt.s = s | ||
354 | cs.attempt.p = &parser{r: s} | ||
355 | return nil | ||
356 | } | ||
357 | |||
278 | // clientStream implements a client side Stream. | 358 | // clientStream implements a client side Stream. |
279 | type clientStream struct { | 359 | type clientStream struct { |
280 | opts []CallOption | 360 | callHdr *transport.CallHdr |
281 | c callInfo | 361 | opts []CallOption |
282 | t transport.ClientTransport | 362 | callInfo *callInfo |
283 | s *transport.Stream | 363 | cc *ClientConn |
284 | p *parser | 364 | desc *StreamDesc |
285 | desc *StreamDesc | 365 | |
286 | codec Codec | 366 | codec baseCodec |
287 | cp Compressor | 367 | cp Compressor |
288 | cbuf *bytes.Buffer | 368 | comp encoding.Compressor |
289 | dc Decompressor | 369 | |
290 | cancel context.CancelFunc | 370 | cancel context.CancelFunc // cancels all attempts |
371 | |||
372 | sentLast bool // sent an end stream | ||
373 | beginTime time.Time | ||
374 | |||
375 | methodConfig *MethodConfig | ||
376 | |||
377 | ctx context.Context // the application's context, wrapped by stats/tracing | ||
291 | 378 | ||
292 | tracing bool // set to EnableTracing when the clientStream is created. | 379 | retryThrottler *retryThrottler // The throttler active when the RPC began. |
293 | 380 | ||
294 | mu sync.Mutex | 381 | binlog *binarylog.MethodLogger // Binary logger, can be nil. |
295 | put func() | 382 | // serverHeaderBinlogged is a boolean for whether server header has been |
296 | closed bool | 383 | // logged. Server header will be logged when the first time one of those |
297 | finished bool | 384 | // happens: stream.Header(), stream.Recv(). |
298 | // trInfo.tr is set when the clientStream is created (if EnableTracing is true), | 385 | // |
299 | // and is set to nil when the clientStream's finish method is called. | 386 | // It's only read and used by Recv() and Header(), so it doesn't need to be |
387 | // synchronized. | ||
388 | serverHeaderBinlogged bool | ||
389 | |||
390 | mu sync.Mutex | ||
391 | firstAttempt bool // if true, transparent retry is valid | ||
392 | numRetries int // exclusive of transparent retry attempt(s) | ||
393 | numRetriesSincePushback int // retries since pushback; to reset backoff | ||
394 | finished bool // TODO: replace with atomic cmpxchg or sync.Once? | ||
395 | attempt *csAttempt // the active client stream attempt | ||
396 | // TODO(hedging): hedging will have multiple attempts simultaneously. | ||
397 | committed bool // active attempt committed for retry? | ||
398 | buffer []func(a *csAttempt) error // operations to replay on retry | ||
399 | bufferSize int // current size of buffer | ||
400 | } | ||
401 | |||
402 | // csAttempt implements a single transport stream attempt within a | ||
403 | // clientStream. | ||
404 | type csAttempt struct { | ||
405 | cs *clientStream | ||
406 | t transport.ClientTransport | ||
407 | s *transport.Stream | ||
408 | p *parser | ||
409 | done func(balancer.DoneInfo) | ||
410 | |||
411 | finished bool | ||
412 | dc Decompressor | ||
413 | decomp encoding.Compressor | ||
414 | decompSet bool | ||
415 | |||
416 | mu sync.Mutex // guards trInfo.tr | ||
417 | // trInfo.tr is set when created (if EnableTracing is true), | ||
418 | // and cleared when the finish method is called. | ||
300 | trInfo traceInfo | 419 | trInfo traceInfo |
301 | 420 | ||
302 | // statsCtx keeps the user context for stats handling. | ||
303 | // All stats collection should use the statsCtx (instead of the stream context) | ||
304 | // so that all the generated stats for a particular RPC can be associated in the processing phase. | ||
305 | statsCtx context.Context | ||
306 | statsHandler stats.Handler | 421 | statsHandler stats.Handler |
307 | } | 422 | } |
308 | 423 | ||
424 | func (cs *clientStream) commitAttemptLocked() { | ||
425 | cs.committed = true | ||
426 | cs.buffer = nil | ||
427 | } | ||
428 | |||
429 | func (cs *clientStream) commitAttempt() { | ||
430 | cs.mu.Lock() | ||
431 | cs.commitAttemptLocked() | ||
432 | cs.mu.Unlock() | ||
433 | } | ||
434 | |||
435 | // shouldRetry returns nil if the RPC should be retried; otherwise it returns | ||
436 | // the error that should be returned by the operation. | ||
437 | func (cs *clientStream) shouldRetry(err error) error { | ||
438 | if cs.attempt.s == nil && !cs.callInfo.failFast { | ||
439 | // In the event of any error from NewStream (attempt.s == nil), we | ||
440 | // never attempted to write anything to the wire, so we can retry | ||
441 | // indefinitely for non-fail-fast RPCs. | ||
442 | return nil | ||
443 | } | ||
444 | if cs.finished || cs.committed { | ||
445 | // RPC is finished or committed; cannot retry. | ||
446 | return err | ||
447 | } | ||
448 | // Wait for the trailers. | ||
449 | if cs.attempt.s != nil { | ||
450 | <-cs.attempt.s.Done() | ||
451 | } | ||
452 | if cs.firstAttempt && !cs.callInfo.failFast && (cs.attempt.s == nil || cs.attempt.s.Unprocessed()) { | ||
453 | // First attempt, wait-for-ready, stream unprocessed: transparently retry. | ||
454 | cs.firstAttempt = false | ||
455 | return nil | ||
456 | } | ||
457 | cs.firstAttempt = false | ||
458 | if cs.cc.dopts.disableRetry { | ||
459 | return err | ||
460 | } | ||
461 | |||
462 | pushback := 0 | ||
463 | hasPushback := false | ||
464 | if cs.attempt.s != nil { | ||
465 | if to, toErr := cs.attempt.s.TrailersOnly(); toErr != nil || !to { | ||
466 | return err | ||
467 | } | ||
468 | |||
469 | // TODO(retry): Move down if the spec changes to not check server pushback | ||
470 | // before considering this a failure for throttling. | ||
471 | sps := cs.attempt.s.Trailer()["grpc-retry-pushback-ms"] | ||
472 | if len(sps) == 1 { | ||
473 | var e error | ||
474 | if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { | ||
475 | grpclog.Infof("Server retry pushback specified to abort (%q).", sps[0]) | ||
476 | cs.retryThrottler.throttle() // This counts as a failure for throttling. | ||
477 | return err | ||
478 | } | ||
479 | hasPushback = true | ||
480 | } else if len(sps) > 1 { | ||
481 | grpclog.Warningf("Server retry pushback specified multiple values (%q); not retrying.", sps) | ||
482 | cs.retryThrottler.throttle() // This counts as a failure for throttling. | ||
483 | return err | ||
484 | } | ||
485 | } | ||
486 | |||
487 | var code codes.Code | ||
488 | if cs.attempt.s != nil { | ||
489 | code = cs.attempt.s.Status().Code() | ||
490 | } else { | ||
491 | code = status.Convert(err).Code() | ||
492 | } | ||
493 | |||
494 | rp := cs.methodConfig.retryPolicy | ||
495 | if rp == nil || !rp.retryableStatusCodes[code] { | ||
496 | return err | ||
497 | } | ||
498 | |||
499 | // Note: the ordering here is important; we count this as a failure | ||
500 | // only if the code matched a retryable code. | ||
501 | if cs.retryThrottler.throttle() { | ||
502 | return err | ||
503 | } | ||
504 | if cs.numRetries+1 >= rp.maxAttempts { | ||
505 | return err | ||
506 | } | ||
507 | |||
508 | var dur time.Duration | ||
509 | if hasPushback { | ||
510 | dur = time.Millisecond * time.Duration(pushback) | ||
511 | cs.numRetriesSincePushback = 0 | ||
512 | } else { | ||
513 | fact := math.Pow(rp.backoffMultiplier, float64(cs.numRetriesSincePushback)) | ||
514 | cur := float64(rp.initialBackoff) * fact | ||
515 | if max := float64(rp.maxBackoff); cur > max { | ||
516 | cur = max | ||
517 | } | ||
518 | dur = time.Duration(grpcrand.Int63n(int64(cur))) | ||
519 | cs.numRetriesSincePushback++ | ||
520 | } | ||
521 | |||
522 | // TODO(dfawley): we could eagerly fail here if dur puts us past the | ||
523 | // deadline, but unsure if it is worth doing. | ||
524 | t := time.NewTimer(dur) | ||
525 | select { | ||
526 | case <-t.C: | ||
527 | cs.numRetries++ | ||
528 | return nil | ||
529 | case <-cs.ctx.Done(): | ||
530 | t.Stop() | ||
531 | return status.FromContextError(cs.ctx.Err()).Err() | ||
532 | } | ||
533 | } | ||
534 | |||
535 | // Returns nil if a retry was performed and succeeded; error otherwise. | ||
536 | func (cs *clientStream) retryLocked(lastErr error) error { | ||
537 | for { | ||
538 | cs.attempt.finish(lastErr) | ||
539 | if err := cs.shouldRetry(lastErr); err != nil { | ||
540 | cs.commitAttemptLocked() | ||
541 | return err | ||
542 | } | ||
543 | if err := cs.newAttemptLocked(nil, traceInfo{}); err != nil { | ||
544 | return err | ||
545 | } | ||
546 | if lastErr = cs.replayBufferLocked(); lastErr == nil { | ||
547 | return nil | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
309 | func (cs *clientStream) Context() context.Context { | 552 | func (cs *clientStream) Context() context.Context { |
310 | return cs.s.Context() | 553 | cs.commitAttempt() |
554 | // No need to lock before using attempt, since we know it is committed and | ||
555 | // cannot change. | ||
556 | return cs.attempt.s.Context() | ||
557 | } | ||
558 | |||
559 | func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) error { | ||
560 | cs.mu.Lock() | ||
561 | for { | ||
562 | if cs.committed { | ||
563 | cs.mu.Unlock() | ||
564 | return op(cs.attempt) | ||
565 | } | ||
566 | a := cs.attempt | ||
567 | cs.mu.Unlock() | ||
568 | err := op(a) | ||
569 | cs.mu.Lock() | ||
570 | if a != cs.attempt { | ||
571 | // We started another attempt already. | ||
572 | continue | ||
573 | } | ||
574 | if err == io.EOF { | ||
575 | <-a.s.Done() | ||
576 | } | ||
577 | if err == nil || (err == io.EOF && a.s.Status().Code() == codes.OK) { | ||
578 | onSuccess() | ||
579 | cs.mu.Unlock() | ||
580 | return err | ||
581 | } | ||
582 | if err := cs.retryLocked(err); err != nil { | ||
583 | cs.mu.Unlock() | ||
584 | return err | ||
585 | } | ||
586 | } | ||
311 | } | 587 | } |
312 | 588 | ||
313 | func (cs *clientStream) Header() (metadata.MD, error) { | 589 | func (cs *clientStream) Header() (metadata.MD, error) { |
314 | m, err := cs.s.Header() | 590 | var m metadata.MD |
591 | err := cs.withRetry(func(a *csAttempt) error { | ||
592 | var err error | ||
593 | m, err = a.s.Header() | ||
594 | return toRPCErr(err) | ||
595 | }, cs.commitAttemptLocked) | ||
315 | if err != nil { | 596 | if err != nil { |
316 | if _, ok := err.(transport.ConnectionError); !ok { | 597 | cs.finish(err) |
317 | cs.closeTransportStream(err) | 598 | return nil, err |
599 | } | ||
600 | if cs.binlog != nil && !cs.serverHeaderBinlogged { | ||
601 | // Only log if binary log is on and header has not been logged. | ||
602 | logEntry := &binarylog.ServerHeader{ | ||
603 | OnClientSide: true, | ||
604 | Header: m, | ||
605 | PeerAddr: nil, | ||
318 | } | 606 | } |
607 | if peer, ok := peer.FromContext(cs.Context()); ok { | ||
608 | logEntry.PeerAddr = peer.Addr | ||
609 | } | ||
610 | cs.binlog.Log(logEntry) | ||
611 | cs.serverHeaderBinlogged = true | ||
319 | } | 612 | } |
320 | return m, err | 613 | return m, err |
321 | } | 614 | } |
322 | 615 | ||
323 | func (cs *clientStream) Trailer() metadata.MD { | 616 | func (cs *clientStream) Trailer() metadata.MD { |
324 | return cs.s.Trailer() | 617 | // On RPC failure, we never need to retry, because usage requires that |
618 | // RecvMsg() returned a non-nil error before calling this function is valid. | ||
619 | // We would have retried earlier if necessary. | ||
620 | // | ||
621 | // Commit the attempt anyway, just in case users are not following those | ||
622 | // directions -- it will prevent races and should not meaningfully impact | ||
623 | // performance. | ||
624 | cs.commitAttempt() | ||
625 | if cs.attempt.s == nil { | ||
626 | return nil | ||
627 | } | ||
628 | return cs.attempt.s.Trailer() | ||
325 | } | 629 | } |
326 | 630 | ||
327 | func (cs *clientStream) SendMsg(m interface{}) (err error) { | 631 | func (cs *clientStream) replayBufferLocked() error { |
328 | if cs.tracing { | 632 | a := cs.attempt |
329 | cs.mu.Lock() | 633 | for _, f := range cs.buffer { |
330 | if cs.trInfo.tr != nil { | 634 | if err := f(a); err != nil { |
331 | cs.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true) | 635 | return err |
332 | } | 636 | } |
333 | cs.mu.Unlock() | ||
334 | } | 637 | } |
335 | // TODO Investigate how to signal the stats handling party. | 638 | return nil |
336 | // generate error stats if err != nil && err != io.EOF? | 639 | } |
640 | |||
641 | func (cs *clientStream) bufferForRetryLocked(sz int, op func(a *csAttempt) error) { | ||
642 | // Note: we still will buffer if retry is disabled (for transparent retries). | ||
643 | if cs.committed { | ||
644 | return | ||
645 | } | ||
646 | cs.bufferSize += sz | ||
647 | if cs.bufferSize > cs.callInfo.maxRetryRPCBufferSize { | ||
648 | cs.commitAttemptLocked() | ||
649 | return | ||
650 | } | ||
651 | cs.buffer = append(cs.buffer, op) | ||
652 | } | ||
653 | |||
654 | func (cs *clientStream) SendMsg(m interface{}) (err error) { | ||
337 | defer func() { | 655 | defer func() { |
338 | if err != nil { | 656 | if err != nil && err != io.EOF { |
657 | // Call finish on the client stream for errors generated by this SendMsg | ||
658 | // call, as these indicate problems created by this client. (Transport | ||
659 | // errors are converted to an io.EOF error in csAttempt.sendMsg; the real | ||
660 | // error will be returned from RecvMsg eventually in that case, or be | ||
661 | // retried.) | ||
339 | cs.finish(err) | 662 | cs.finish(err) |
340 | } | 663 | } |
341 | if err == nil { | ||
342 | return | ||
343 | } | ||
344 | if err == io.EOF { | ||
345 | // Specialize the process for server streaming. SendMesg is only called | ||
346 | // once when creating the stream object. io.EOF needs to be skipped when | ||
347 | // the rpc is early finished (before the stream object is created.). | ||
348 | // TODO: It is probably better to move this into the generated code. | ||
349 | if !cs.desc.ClientStreams && cs.desc.ServerStreams { | ||
350 | err = nil | ||
351 | } | ||
352 | return | ||
353 | } | ||
354 | if _, ok := err.(transport.ConnectionError); !ok { | ||
355 | cs.closeTransportStream(err) | ||
356 | } | ||
357 | err = toRPCErr(err) | ||
358 | }() | 664 | }() |
359 | var outPayload *stats.OutPayload | 665 | if cs.sentLast { |
360 | if cs.statsHandler != nil { | 666 | return status.Errorf(codes.Internal, "SendMsg called after CloseSend") |
361 | outPayload = &stats.OutPayload{ | ||
362 | Client: true, | ||
363 | } | ||
364 | } | 667 | } |
365 | out, err := encode(cs.codec, m, cs.cp, cs.cbuf, outPayload) | 668 | if !cs.desc.ClientStreams { |
366 | defer func() { | 669 | cs.sentLast = true |
367 | if cs.cbuf != nil { | 670 | } |
368 | cs.cbuf.Reset() | 671 | data, err := encode(cs.codec, m) |
369 | } | ||
370 | }() | ||
371 | if err != nil { | 672 | if err != nil { |
372 | return err | 673 | return err |
373 | } | 674 | } |
374 | if cs.c.maxSendMessageSize == nil { | 675 | compData, err := compress(data, cs.cp, cs.comp) |
375 | return Errorf(codes.Internal, "callInfo maxSendMessageSize field uninitialized(nil)") | 676 | if err != nil { |
677 | return err | ||
376 | } | 678 | } |
377 | if len(out) > *cs.c.maxSendMessageSize { | 679 | hdr, payload := msgHeader(data, compData) |
378 | return Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(out), *cs.c.maxSendMessageSize) | 680 | // TODO(dfawley): should we be checking len(data) instead? |
681 | if len(payload) > *cs.callInfo.maxSendMessageSize { | ||
682 | return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), *cs.callInfo.maxSendMessageSize) | ||
379 | } | 683 | } |
380 | err = cs.t.Write(cs.s, out, &transport.Options{Last: false}) | 684 | msgBytes := data // Store the pointer before setting to nil. For binary logging. |
381 | if err == nil && outPayload != nil { | 685 | op := func(a *csAttempt) error { |
382 | outPayload.SentTime = time.Now() | 686 | err := a.sendMsg(m, hdr, payload, data) |
383 | cs.statsHandler.HandleRPC(cs.statsCtx, outPayload) | 687 | // nil out the message and uncomp when replaying; they are only needed for |
688 | // stats which is disabled for subsequent attempts. | ||
689 | m, data = nil, nil | ||
690 | return err | ||
384 | } | 691 | } |
385 | return err | 692 | err = cs.withRetry(op, func() { cs.bufferForRetryLocked(len(hdr)+len(payload), op) }) |
693 | if cs.binlog != nil && err == nil { | ||
694 | cs.binlog.Log(&binarylog.ClientMessage{ | ||
695 | OnClientSide: true, | ||
696 | Message: msgBytes, | ||
697 | }) | ||
698 | } | ||
699 | return | ||
386 | } | 700 | } |
387 | 701 | ||
388 | func (cs *clientStream) RecvMsg(m interface{}) (err error) { | 702 | func (cs *clientStream) RecvMsg(m interface{}) error { |
389 | var inPayload *stats.InPayload | 703 | if cs.binlog != nil && !cs.serverHeaderBinlogged { |
390 | if cs.statsHandler != nil { | 704 | // Call Header() to binary log header if it's not already logged. |
391 | inPayload = &stats.InPayload{ | 705 | cs.Header() |
392 | Client: true, | ||
393 | } | ||
394 | } | 706 | } |
395 | if cs.c.maxReceiveMessageSize == nil { | 707 | var recvInfo *payloadInfo |
396 | return Errorf(codes.Internal, "callInfo maxReceiveMessageSize field uninitialized(nil)") | 708 | if cs.binlog != nil { |
709 | recvInfo = &payloadInfo{} | ||
397 | } | 710 | } |
398 | err = recv(cs.p, cs.codec, cs.s, cs.dc, m, *cs.c.maxReceiveMessageSize, inPayload) | 711 | err := cs.withRetry(func(a *csAttempt) error { |
399 | defer func() { | 712 | return a.recvMsg(m, recvInfo) |
400 | // err != nil indicates the termination of the stream. | 713 | }, cs.commitAttemptLocked) |
401 | if err != nil { | 714 | if cs.binlog != nil && err == nil { |
402 | cs.finish(err) | 715 | cs.binlog.Log(&binarylog.ServerMessage{ |
716 | OnClientSide: true, | ||
717 | Message: recvInfo.uncompressedBytes, | ||
718 | }) | ||
719 | } | ||
720 | if err != nil || !cs.desc.ServerStreams { | ||
721 | // err != nil or non-server-streaming indicates end of stream. | ||
722 | cs.finish(err) | ||
723 | |||
724 | if cs.binlog != nil { | ||
725 | // finish will not log Trailer. Log Trailer here. | ||
726 | logEntry := &binarylog.ServerTrailer{ | ||
727 | OnClientSide: true, | ||
728 | Trailer: cs.Trailer(), | ||
729 | Err: err, | ||
730 | } | ||
731 | if logEntry.Err == io.EOF { | ||
732 | logEntry.Err = nil | ||
733 | } | ||
734 | if peer, ok := peer.FromContext(cs.Context()); ok { | ||
735 | logEntry.PeerAddr = peer.Addr | ||
736 | } | ||
737 | cs.binlog.Log(logEntry) | ||
403 | } | 738 | } |
404 | }() | 739 | } |
740 | return err | ||
741 | } | ||
742 | |||
743 | func (cs *clientStream) CloseSend() error { | ||
744 | if cs.sentLast { | ||
745 | // TODO: return an error and finish the stream instead, due to API misuse? | ||
746 | return nil | ||
747 | } | ||
748 | cs.sentLast = true | ||
749 | op := func(a *csAttempt) error { | ||
750 | a.t.Write(a.s, nil, nil, &transport.Options{Last: true}) | ||
751 | // Always return nil; io.EOF is the only error that might make sense | ||
752 | // instead, but there is no need to signal the client to call RecvMsg | ||
753 | // as the only use left for the stream after CloseSend is to call | ||
754 | // RecvMsg. This also matches historical behavior. | ||
755 | return nil | ||
756 | } | ||
757 | cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }) | ||
758 | if cs.binlog != nil { | ||
759 | cs.binlog.Log(&binarylog.ClientHalfClose{ | ||
760 | OnClientSide: true, | ||
761 | }) | ||
762 | } | ||
763 | // We never returned an error here for reasons. | ||
764 | return nil | ||
765 | } | ||
766 | |||
767 | func (cs *clientStream) finish(err error) { | ||
768 | if err == io.EOF { | ||
769 | // Ending a stream with EOF indicates a success. | ||
770 | err = nil | ||
771 | } | ||
772 | cs.mu.Lock() | ||
773 | if cs.finished { | ||
774 | cs.mu.Unlock() | ||
775 | return | ||
776 | } | ||
777 | cs.finished = true | ||
778 | cs.commitAttemptLocked() | ||
779 | cs.mu.Unlock() | ||
780 | // For binary logging. only log cancel in finish (could be caused by RPC ctx | ||
781 | // canceled or ClientConn closed). Trailer will be logged in RecvMsg. | ||
782 | // | ||
783 | // Only one of cancel or trailer needs to be logged. In the cases where | ||
784 | // users don't call RecvMsg, users must have already canceled the RPC. | ||
785 | if cs.binlog != nil && status.Code(err) == codes.Canceled { | ||
786 | cs.binlog.Log(&binarylog.Cancel{ | ||
787 | OnClientSide: true, | ||
788 | }) | ||
789 | } | ||
405 | if err == nil { | 790 | if err == nil { |
406 | if cs.tracing { | 791 | cs.retryThrottler.successfulRPC() |
407 | cs.mu.Lock() | 792 | } |
408 | if cs.trInfo.tr != nil { | 793 | if channelz.IsOn() { |
409 | cs.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true) | 794 | if err != nil { |
410 | } | 795 | cs.cc.incrCallsFailed() |
411 | cs.mu.Unlock() | 796 | } else { |
797 | cs.cc.incrCallsSucceeded() | ||
412 | } | 798 | } |
413 | if inPayload != nil { | 799 | } |
414 | cs.statsHandler.HandleRPC(cs.statsCtx, inPayload) | 800 | if cs.attempt != nil { |
801 | cs.attempt.finish(err) | ||
802 | } | ||
803 | // after functions all rely upon having a stream. | ||
804 | if cs.attempt.s != nil { | ||
805 | for _, o := range cs.opts { | ||
806 | o.after(cs.callInfo) | ||
415 | } | 807 | } |
416 | if !cs.desc.ClientStreams || cs.desc.ServerStreams { | 808 | } |
417 | return | 809 | cs.cancel() |
810 | } | ||
811 | |||
812 | func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { | ||
813 | cs := a.cs | ||
814 | if EnableTracing { | ||
815 | a.mu.Lock() | ||
816 | if a.trInfo.tr != nil { | ||
817 | a.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true) | ||
418 | } | 818 | } |
419 | // Special handling for client streaming rpc. | 819 | a.mu.Unlock() |
420 | // This recv expects EOF or errors, so we don't collect inPayload. | 820 | } |
421 | if cs.c.maxReceiveMessageSize == nil { | 821 | if err := a.t.Write(a.s, hdr, payld, &transport.Options{Last: !cs.desc.ClientStreams}); err != nil { |
422 | return Errorf(codes.Internal, "callInfo maxReceiveMessageSize field uninitialized(nil)") | 822 | if !cs.desc.ClientStreams { |
823 | // For non-client-streaming RPCs, we return nil instead of EOF on error | ||
824 | // because the generated code requires it. finish is not called; RecvMsg() | ||
825 | // will call it with the stream's status independently. | ||
826 | return nil | ||
423 | } | 827 | } |
424 | err = recv(cs.p, cs.codec, cs.s, cs.dc, m, *cs.c.maxReceiveMessageSize, nil) | 828 | return io.EOF |
425 | cs.closeTransportStream(err) | 829 | } |
426 | if err == nil { | 830 | if a.statsHandler != nil { |
427 | return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>")) | 831 | a.statsHandler.HandleRPC(cs.ctx, outPayload(true, m, data, payld, time.Now())) |
832 | } | ||
833 | if channelz.IsOn() { | ||
834 | a.t.IncrMsgSent() | ||
835 | } | ||
836 | return nil | ||
837 | } | ||
838 | |||
839 | func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { | ||
840 | cs := a.cs | ||
841 | if a.statsHandler != nil && payInfo == nil { | ||
842 | payInfo = &payloadInfo{} | ||
843 | } | ||
844 | |||
845 | if !a.decompSet { | ||
846 | // Block until we receive headers containing received message encoding. | ||
847 | if ct := a.s.RecvCompress(); ct != "" && ct != encoding.Identity { | ||
848 | if a.dc == nil || a.dc.Type() != ct { | ||
849 | // No configured decompressor, or it does not match the incoming | ||
850 | // message encoding; attempt to find a registered compressor that does. | ||
851 | a.dc = nil | ||
852 | a.decomp = encoding.GetCompressor(ct) | ||
853 | } | ||
854 | } else { | ||
855 | // No compression is used; disable our decompressor. | ||
856 | a.dc = nil | ||
428 | } | 857 | } |
858 | // Only initialize this state once per stream. | ||
859 | a.decompSet = true | ||
860 | } | ||
861 | err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, payInfo, a.decomp) | ||
862 | if err != nil { | ||
429 | if err == io.EOF { | 863 | if err == io.EOF { |
430 | if se := cs.s.Status().Err(); se != nil { | 864 | if statusErr := a.s.Status().Err(); statusErr != nil { |
431 | return se | 865 | return statusErr |
432 | } | 866 | } |
433 | cs.finish(err) | 867 | return io.EOF // indicates successful end of stream. |
434 | return nil | ||
435 | } | 868 | } |
436 | return toRPCErr(err) | 869 | return toRPCErr(err) |
437 | } | 870 | } |
438 | if _, ok := err.(transport.ConnectionError); !ok { | 871 | if EnableTracing { |
439 | cs.closeTransportStream(err) | 872 | a.mu.Lock() |
873 | if a.trInfo.tr != nil { | ||
874 | a.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true) | ||
875 | } | ||
876 | a.mu.Unlock() | ||
877 | } | ||
878 | if a.statsHandler != nil { | ||
879 | a.statsHandler.HandleRPC(cs.ctx, &stats.InPayload{ | ||
880 | Client: true, | ||
881 | RecvTime: time.Now(), | ||
882 | Payload: m, | ||
883 | // TODO truncate large payload. | ||
884 | Data: payInfo.uncompressedBytes, | ||
885 | Length: len(payInfo.uncompressedBytes), | ||
886 | }) | ||
887 | } | ||
888 | if channelz.IsOn() { | ||
889 | a.t.IncrMsgRecv() | ||
890 | } | ||
891 | if cs.desc.ServerStreams { | ||
892 | // Subsequent messages should be received by subsequent RecvMsg calls. | ||
893 | return nil | ||
894 | } | ||
895 | // Special handling for non-server-stream rpcs. | ||
896 | // This recv expects EOF or errors, so we don't collect inPayload. | ||
897 | err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decomp) | ||
898 | if err == nil { | ||
899 | return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>")) | ||
440 | } | 900 | } |
441 | if err == io.EOF { | 901 | if err == io.EOF { |
442 | if statusErr := cs.s.Status().Err(); statusErr != nil { | 902 | return a.s.Status().Err() // non-server streaming Recv returns nil on success |
443 | return statusErr | ||
444 | } | ||
445 | // Returns io.EOF to indicate the end of the stream. | ||
446 | return | ||
447 | } | 903 | } |
448 | return toRPCErr(err) | 904 | return toRPCErr(err) |
449 | } | 905 | } |
450 | 906 | ||
451 | func (cs *clientStream) CloseSend() (err error) { | 907 | func (a *csAttempt) finish(err error) { |
452 | err = cs.t.Write(cs.s, nil, &transport.Options{Last: true}) | 908 | a.mu.Lock() |
909 | if a.finished { | ||
910 | a.mu.Unlock() | ||
911 | return | ||
912 | } | ||
913 | a.finished = true | ||
914 | if err == io.EOF { | ||
915 | // Ending a stream with EOF indicates a success. | ||
916 | err = nil | ||
917 | } | ||
918 | if a.s != nil { | ||
919 | a.t.CloseStream(a.s, err) | ||
920 | } | ||
921 | |||
922 | if a.done != nil { | ||
923 | br := false | ||
924 | var tr metadata.MD | ||
925 | if a.s != nil { | ||
926 | br = a.s.BytesReceived() | ||
927 | tr = a.s.Trailer() | ||
928 | } | ||
929 | a.done(balancer.DoneInfo{ | ||
930 | Err: err, | ||
931 | Trailer: tr, | ||
932 | BytesSent: a.s != nil, | ||
933 | BytesReceived: br, | ||
934 | }) | ||
935 | } | ||
936 | if a.statsHandler != nil { | ||
937 | end := &stats.End{ | ||
938 | Client: true, | ||
939 | BeginTime: a.cs.beginTime, | ||
940 | EndTime: time.Now(), | ||
941 | Error: err, | ||
942 | } | ||
943 | a.statsHandler.HandleRPC(a.cs.ctx, end) | ||
944 | } | ||
945 | if a.trInfo.tr != nil { | ||
946 | if err == nil { | ||
947 | a.trInfo.tr.LazyPrintf("RPC: [OK]") | ||
948 | } else { | ||
949 | a.trInfo.tr.LazyPrintf("RPC: [%v]", err) | ||
950 | a.trInfo.tr.SetError() | ||
951 | } | ||
952 | a.trInfo.tr.Finish() | ||
953 | a.trInfo.tr = nil | ||
954 | } | ||
955 | a.mu.Unlock() | ||
956 | } | ||
957 | |||
958 | func (ac *addrConn) newClientStream(ctx context.Context, desc *StreamDesc, method string, t transport.ClientTransport, opts ...CallOption) (_ ClientStream, err error) { | ||
959 | ac.mu.Lock() | ||
960 | if ac.transport != t { | ||
961 | ac.mu.Unlock() | ||
962 | return nil, status.Error(codes.Canceled, "the provided transport is no longer valid to use") | ||
963 | } | ||
964 | // transition to CONNECTING state when an attempt starts | ||
965 | if ac.state != connectivity.Connecting { | ||
966 | ac.updateConnectivityState(connectivity.Connecting) | ||
967 | ac.cc.handleSubConnStateChange(ac.acbw, ac.state) | ||
968 | } | ||
969 | ac.mu.Unlock() | ||
970 | |||
971 | if t == nil { | ||
972 | // TODO: return RPC error here? | ||
973 | return nil, errors.New("transport provided is nil") | ||
974 | } | ||
975 | // defaultCallInfo contains unnecessary info(i.e. failfast, maxRetryRPCBufferSize), so we just initialize an empty struct. | ||
976 | c := &callInfo{} | ||
977 | |||
978 | for _, o := range opts { | ||
979 | if err := o.before(c); err != nil { | ||
980 | return nil, toRPCErr(err) | ||
981 | } | ||
982 | } | ||
983 | c.maxReceiveMessageSize = getMaxSize(nil, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) | ||
984 | c.maxSendMessageSize = getMaxSize(nil, c.maxSendMessageSize, defaultServerMaxSendMessageSize) | ||
985 | |||
986 | // Possible context leak: | ||
987 | // The cancel function for the child context we create will only be called | ||
988 | // when RecvMsg returns a non-nil error, if the ClientConn is closed, or if | ||
989 | // an error is generated by SendMsg. | ||
990 | // https://github.com/grpc/grpc-go/issues/1818. | ||
991 | ctx, cancel := context.WithCancel(ctx) | ||
453 | defer func() { | 992 | defer func() { |
454 | if err != nil { | 993 | if err != nil { |
455 | cs.finish(err) | 994 | cancel() |
456 | } | 995 | } |
457 | }() | 996 | }() |
458 | if err == nil || err == io.EOF { | 997 | |
459 | return nil | 998 | if err := setCallInfoCodec(c); err != nil { |
999 | return nil, err | ||
460 | } | 1000 | } |
461 | if _, ok := err.(transport.ConnectionError); !ok { | 1001 | |
462 | cs.closeTransportStream(err) | 1002 | callHdr := &transport.CallHdr{ |
1003 | Host: ac.cc.authority, | ||
1004 | Method: method, | ||
1005 | ContentSubtype: c.contentSubtype, | ||
463 | } | 1006 | } |
464 | err = toRPCErr(err) | 1007 | |
465 | return | 1008 | // Set our outgoing compression according to the UseCompressor CallOption, if |
1009 | // set. In that case, also find the compressor from the encoding package. | ||
1010 | // Otherwise, use the compressor configured by the WithCompressor DialOption, | ||
1011 | // if set. | ||
1012 | var cp Compressor | ||
1013 | var comp encoding.Compressor | ||
1014 | if ct := c.compressorType; ct != "" { | ||
1015 | callHdr.SendCompress = ct | ||
1016 | if ct != encoding.Identity { | ||
1017 | comp = encoding.GetCompressor(ct) | ||
1018 | if comp == nil { | ||
1019 | return nil, status.Errorf(codes.Internal, "grpc: Compressor is not installed for requested grpc-encoding %q", ct) | ||
1020 | } | ||
1021 | } | ||
1022 | } else if ac.cc.dopts.cp != nil { | ||
1023 | callHdr.SendCompress = ac.cc.dopts.cp.Type() | ||
1024 | cp = ac.cc.dopts.cp | ||
1025 | } | ||
1026 | if c.creds != nil { | ||
1027 | callHdr.Creds = c.creds | ||
1028 | } | ||
1029 | |||
1030 | as := &addrConnStream{ | ||
1031 | callHdr: callHdr, | ||
1032 | ac: ac, | ||
1033 | ctx: ctx, | ||
1034 | cancel: cancel, | ||
1035 | opts: opts, | ||
1036 | callInfo: c, | ||
1037 | desc: desc, | ||
1038 | codec: c.codec, | ||
1039 | cp: cp, | ||
1040 | comp: comp, | ||
1041 | t: t, | ||
1042 | } | ||
1043 | |||
1044 | as.callInfo.stream = as | ||
1045 | s, err := as.t.NewStream(as.ctx, as.callHdr) | ||
1046 | if err != nil { | ||
1047 | err = toRPCErr(err) | ||
1048 | return nil, err | ||
1049 | } | ||
1050 | as.s = s | ||
1051 | as.p = &parser{r: s} | ||
1052 | ac.incrCallsStarted() | ||
1053 | if desc != unaryStreamDesc { | ||
1054 | // Listen on cc and stream contexts to cleanup when the user closes the | ||
1055 | // ClientConn or cancels the stream context. In all other cases, an error | ||
1056 | // should already be injected into the recv buffer by the transport, which | ||
1057 | // the client will eventually receive, and then we will cancel the stream's | ||
1058 | // context in clientStream.finish. | ||
1059 | go func() { | ||
1060 | select { | ||
1061 | case <-ac.ctx.Done(): | ||
1062 | as.finish(status.Error(codes.Canceled, "grpc: the SubConn is closing")) | ||
1063 | case <-ctx.Done(): | ||
1064 | as.finish(toRPCErr(ctx.Err())) | ||
1065 | } | ||
1066 | }() | ||
1067 | } | ||
1068 | return as, nil | ||
466 | } | 1069 | } |
467 | 1070 | ||
468 | func (cs *clientStream) closeTransportStream(err error) { | 1071 | type addrConnStream struct { |
469 | cs.mu.Lock() | 1072 | s *transport.Stream |
470 | if cs.closed { | 1073 | ac *addrConn |
471 | cs.mu.Unlock() | 1074 | callHdr *transport.CallHdr |
472 | return | 1075 | cancel context.CancelFunc |
1076 | opts []CallOption | ||
1077 | callInfo *callInfo | ||
1078 | t transport.ClientTransport | ||
1079 | ctx context.Context | ||
1080 | sentLast bool | ||
1081 | desc *StreamDesc | ||
1082 | codec baseCodec | ||
1083 | cp Compressor | ||
1084 | comp encoding.Compressor | ||
1085 | decompSet bool | ||
1086 | dc Decompressor | ||
1087 | decomp encoding.Compressor | ||
1088 | p *parser | ||
1089 | done func(balancer.DoneInfo) | ||
1090 | mu sync.Mutex | ||
1091 | finished bool | ||
1092 | } | ||
1093 | |||
1094 | func (as *addrConnStream) Header() (metadata.MD, error) { | ||
1095 | m, err := as.s.Header() | ||
1096 | if err != nil { | ||
1097 | as.finish(toRPCErr(err)) | ||
473 | } | 1098 | } |
474 | cs.closed = true | 1099 | return m, err |
475 | cs.mu.Unlock() | ||
476 | cs.t.CloseStream(cs.s, err) | ||
477 | } | 1100 | } |
478 | 1101 | ||
479 | func (cs *clientStream) finish(err error) { | 1102 | func (as *addrConnStream) Trailer() metadata.MD { |
480 | cs.mu.Lock() | 1103 | return as.s.Trailer() |
481 | defer cs.mu.Unlock() | 1104 | } |
482 | if cs.finished { | 1105 | |
483 | return | 1106 | func (as *addrConnStream) CloseSend() error { |
1107 | if as.sentLast { | ||
1108 | // TODO: return an error and finish the stream instead, due to API misuse? | ||
1109 | return nil | ||
484 | } | 1110 | } |
485 | cs.finished = true | 1111 | as.sentLast = true |
1112 | |||
1113 | as.t.Write(as.s, nil, nil, &transport.Options{Last: true}) | ||
1114 | // Always return nil; io.EOF is the only error that might make sense | ||
1115 | // instead, but there is no need to signal the client to call RecvMsg | ||
1116 | // as the only use left for the stream after CloseSend is to call | ||
1117 | // RecvMsg. This also matches historical behavior. | ||
1118 | return nil | ||
1119 | } | ||
1120 | |||
1121 | func (as *addrConnStream) Context() context.Context { | ||
1122 | return as.s.Context() | ||
1123 | } | ||
1124 | |||
1125 | func (as *addrConnStream) SendMsg(m interface{}) (err error) { | ||
486 | defer func() { | 1126 | defer func() { |
487 | if cs.cancel != nil { | 1127 | if err != nil && err != io.EOF { |
488 | cs.cancel() | 1128 | // Call finish on the client stream for errors generated by this SendMsg |
1129 | // call, as these indicate problems created by this client. (Transport | ||
1130 | // errors are converted to an io.EOF error in csAttempt.sendMsg; the real | ||
1131 | // error will be returned from RecvMsg eventually in that case, or be | ||
1132 | // retried.) | ||
1133 | as.finish(err) | ||
489 | } | 1134 | } |
490 | }() | 1135 | }() |
491 | for _, o := range cs.opts { | 1136 | if as.sentLast { |
492 | o.after(&cs.c) | 1137 | return status.Errorf(codes.Internal, "SendMsg called after CloseSend") |
493 | } | 1138 | } |
494 | if cs.put != nil { | 1139 | if !as.desc.ClientStreams { |
495 | updateRPCInfoInContext(cs.s.Context(), rpcInfo{ | 1140 | as.sentLast = true |
496 | bytesSent: cs.s.BytesSent(), | ||
497 | bytesReceived: cs.s.BytesReceived(), | ||
498 | }) | ||
499 | cs.put() | ||
500 | cs.put = nil | ||
501 | } | 1141 | } |
502 | if cs.statsHandler != nil { | 1142 | data, err := encode(as.codec, m) |
503 | end := &stats.End{ | 1143 | if err != nil { |
504 | Client: true, | 1144 | return err |
505 | EndTime: time.Now(), | 1145 | } |
506 | } | 1146 | compData, err := compress(data, as.cp, as.comp) |
507 | if err != io.EOF { | 1147 | if err != nil { |
508 | // end.Error is nil if the RPC finished successfully. | 1148 | return err |
509 | end.Error = toRPCErr(err) | 1149 | } |
1150 | hdr, payld := msgHeader(data, compData) | ||
1151 | // TODO(dfawley): should we be checking len(data) instead? | ||
1152 | if len(payld) > *as.callInfo.maxSendMessageSize { | ||
1153 | return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payld), *as.callInfo.maxSendMessageSize) | ||
1154 | } | ||
1155 | |||
1156 | if err := as.t.Write(as.s, hdr, payld, &transport.Options{Last: !as.desc.ClientStreams}); err != nil { | ||
1157 | if !as.desc.ClientStreams { | ||
1158 | // For non-client-streaming RPCs, we return nil instead of EOF on error | ||
1159 | // because the generated code requires it. finish is not called; RecvMsg() | ||
1160 | // will call it with the stream's status independently. | ||
1161 | return nil | ||
510 | } | 1162 | } |
511 | cs.statsHandler.HandleRPC(cs.statsCtx, end) | 1163 | return io.EOF |
512 | } | 1164 | } |
513 | if !cs.tracing { | 1165 | |
514 | return | 1166 | if channelz.IsOn() { |
1167 | as.t.IncrMsgSent() | ||
515 | } | 1168 | } |
516 | if cs.trInfo.tr != nil { | 1169 | return nil |
517 | if err == nil || err == io.EOF { | 1170 | } |
518 | cs.trInfo.tr.LazyPrintf("RPC: [OK]") | 1171 | |
1172 | func (as *addrConnStream) RecvMsg(m interface{}) (err error) { | ||
1173 | defer func() { | ||
1174 | if err != nil || !as.desc.ServerStreams { | ||
1175 | // err != nil or non-server-streaming indicates end of stream. | ||
1176 | as.finish(err) | ||
1177 | } | ||
1178 | }() | ||
1179 | |||
1180 | if !as.decompSet { | ||
1181 | // Block until we receive headers containing received message encoding. | ||
1182 | if ct := as.s.RecvCompress(); ct != "" && ct != encoding.Identity { | ||
1183 | if as.dc == nil || as.dc.Type() != ct { | ||
1184 | // No configured decompressor, or it does not match the incoming | ||
1185 | // message encoding; attempt to find a registered compressor that does. | ||
1186 | as.dc = nil | ||
1187 | as.decomp = encoding.GetCompressor(ct) | ||
1188 | } | ||
519 | } else { | 1189 | } else { |
520 | cs.trInfo.tr.LazyPrintf("RPC: [%v]", err) | 1190 | // No compression is used; disable our decompressor. |
521 | cs.trInfo.tr.SetError() | 1191 | as.dc = nil |
522 | } | 1192 | } |
523 | cs.trInfo.tr.Finish() | 1193 | // Only initialize this state once per stream. |
524 | cs.trInfo.tr = nil | 1194 | as.decompSet = true |
1195 | } | ||
1196 | err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) | ||
1197 | if err != nil { | ||
1198 | if err == io.EOF { | ||
1199 | if statusErr := as.s.Status().Err(); statusErr != nil { | ||
1200 | return statusErr | ||
1201 | } | ||
1202 | return io.EOF // indicates successful end of stream. | ||
1203 | } | ||
1204 | return toRPCErr(err) | ||
1205 | } | ||
1206 | |||
1207 | if channelz.IsOn() { | ||
1208 | as.t.IncrMsgRecv() | ||
525 | } | 1209 | } |
1210 | if as.desc.ServerStreams { | ||
1211 | // Subsequent messages should be received by subsequent RecvMsg calls. | ||
1212 | return nil | ||
1213 | } | ||
1214 | |||
1215 | // Special handling for non-server-stream rpcs. | ||
1216 | // This recv expects EOF or errors, so we don't collect inPayload. | ||
1217 | err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) | ||
1218 | if err == nil { | ||
1219 | return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>")) | ||
1220 | } | ||
1221 | if err == io.EOF { | ||
1222 | return as.s.Status().Err() // non-server streaming Recv returns nil on success | ||
1223 | } | ||
1224 | return toRPCErr(err) | ||
526 | } | 1225 | } |
527 | 1226 | ||
528 | // ServerStream defines the interface a server stream has to satisfy. | 1227 | func (as *addrConnStream) finish(err error) { |
1228 | as.mu.Lock() | ||
1229 | if as.finished { | ||
1230 | as.mu.Unlock() | ||
1231 | return | ||
1232 | } | ||
1233 | as.finished = true | ||
1234 | if err == io.EOF { | ||
1235 | // Ending a stream with EOF indicates a success. | ||
1236 | err = nil | ||
1237 | } | ||
1238 | if as.s != nil { | ||
1239 | as.t.CloseStream(as.s, err) | ||
1240 | } | ||
1241 | |||
1242 | if err != nil { | ||
1243 | as.ac.incrCallsFailed() | ||
1244 | } else { | ||
1245 | as.ac.incrCallsSucceeded() | ||
1246 | } | ||
1247 | as.cancel() | ||
1248 | as.mu.Unlock() | ||
1249 | } | ||
1250 | |||
1251 | // ServerStream defines the server-side behavior of a streaming RPC. | ||
1252 | // | ||
1253 | // All errors returned from ServerStream methods are compatible with the | ||
1254 | // status package. | ||
529 | type ServerStream interface { | 1255 | type ServerStream interface { |
530 | // SetHeader sets the header metadata. It may be called multiple times. | 1256 | // SetHeader sets the header metadata. It may be called multiple times. |
531 | // When call multiple times, all the provided metadata will be merged. | 1257 | // When call multiple times, all the provided metadata will be merged. |
@@ -541,29 +1267,67 @@ type ServerStream interface { | |||
541 | // SetTrailer sets the trailer metadata which will be sent with the RPC status. | 1267 | // SetTrailer sets the trailer metadata which will be sent with the RPC status. |
542 | // When called more than once, all the provided metadata will be merged. | 1268 | // When called more than once, all the provided metadata will be merged. |
543 | SetTrailer(metadata.MD) | 1269 | SetTrailer(metadata.MD) |
544 | Stream | 1270 | // Context returns the context for this stream. |
1271 | Context() context.Context | ||
1272 | // SendMsg sends a message. On error, SendMsg aborts the stream and the | ||
1273 | // error is returned directly. | ||
1274 | // | ||
1275 | // SendMsg blocks until: | ||
1276 | // - There is sufficient flow control to schedule m with the transport, or | ||
1277 | // - The stream is done, or | ||
1278 | // - The stream breaks. | ||
1279 | // | ||
1280 | // SendMsg does not wait until the message is received by the client. An | ||
1281 | // untimely stream closure may result in lost messages. | ||
1282 | // | ||
1283 | // It is safe to have a goroutine calling SendMsg and another goroutine | ||
1284 | // calling RecvMsg on the same stream at the same time, but it is not safe | ||
1285 | // to call SendMsg on the same stream in different goroutines. | ||
1286 | SendMsg(m interface{}) error | ||
1287 | // RecvMsg blocks until it receives a message into m or the stream is | ||
1288 | // done. It returns io.EOF when the client has performed a CloseSend. On | ||
1289 | // any non-EOF error, the stream is aborted and the error contains the | ||
1290 | // RPC status. | ||
1291 | // | ||
1292 | // It is safe to have a goroutine calling SendMsg and another goroutine | ||
1293 | // calling RecvMsg on the same stream at the same time, but it is not | ||
1294 | // safe to call RecvMsg on the same stream in different goroutines. | ||
1295 | RecvMsg(m interface{}) error | ||
545 | } | 1296 | } |
546 | 1297 | ||
547 | // serverStream implements a server side Stream. | 1298 | // serverStream implements a server side Stream. |
548 | type serverStream struct { | 1299 | type serverStream struct { |
549 | t transport.ServerTransport | 1300 | ctx context.Context |
550 | s *transport.Stream | 1301 | t transport.ServerTransport |
551 | p *parser | 1302 | s *transport.Stream |
552 | codec Codec | 1303 | p *parser |
553 | cp Compressor | 1304 | codec baseCodec |
554 | dc Decompressor | 1305 | |
555 | cbuf *bytes.Buffer | 1306 | cp Compressor |
1307 | dc Decompressor | ||
1308 | comp encoding.Compressor | ||
1309 | decomp encoding.Compressor | ||
1310 | |||
556 | maxReceiveMessageSize int | 1311 | maxReceiveMessageSize int |
557 | maxSendMessageSize int | 1312 | maxSendMessageSize int |
558 | trInfo *traceInfo | 1313 | trInfo *traceInfo |
559 | 1314 | ||
560 | statsHandler stats.Handler | 1315 | statsHandler stats.Handler |
561 | 1316 | ||
1317 | binlog *binarylog.MethodLogger | ||
1318 | // serverHeaderBinlogged indicates whether server header has been logged. It | ||
1319 | // will happen when one of the following two happens: stream.SendHeader(), | ||
1320 | // stream.Send(). | ||
1321 | // | ||
1322 | // It's only checked in send and sendHeader, doesn't need to be | ||
1323 | // synchronized. | ||
1324 | serverHeaderBinlogged bool | ||
1325 | |||
562 | mu sync.Mutex // protects trInfo.tr after the service handler runs. | 1326 | mu sync.Mutex // protects trInfo.tr after the service handler runs. |
563 | } | 1327 | } |
564 | 1328 | ||
565 | func (ss *serverStream) Context() context.Context { | 1329 | func (ss *serverStream) Context() context.Context { |
566 | return ss.s.Context() | 1330 | return ss.ctx |
567 | } | 1331 | } |
568 | 1332 | ||
569 | func (ss *serverStream) SetHeader(md metadata.MD) error { | 1333 | func (ss *serverStream) SetHeader(md metadata.MD) error { |
@@ -574,7 +1338,15 @@ func (ss *serverStream) SetHeader(md metadata.MD) error { | |||
574 | } | 1338 | } |
575 | 1339 | ||
576 | func (ss *serverStream) SendHeader(md metadata.MD) error { | 1340 | func (ss *serverStream) SendHeader(md metadata.MD) error { |
577 | return ss.t.WriteHeader(ss.s, md) | 1341 | err := ss.t.WriteHeader(ss.s, md) |
1342 | if ss.binlog != nil && !ss.serverHeaderBinlogged { | ||
1343 | h, _ := ss.s.Header() | ||
1344 | ss.binlog.Log(&binarylog.ServerHeader{ | ||
1345 | Header: h, | ||
1346 | }) | ||
1347 | ss.serverHeaderBinlogged = true | ||
1348 | } | ||
1349 | return err | ||
578 | } | 1350 | } |
579 | 1351 | ||
580 | func (ss *serverStream) SetTrailer(md metadata.MD) { | 1352 | func (ss *serverStream) SetTrailer(md metadata.MD) { |
@@ -582,7 +1354,6 @@ func (ss *serverStream) SetTrailer(md metadata.MD) { | |||
582 | return | 1354 | return |
583 | } | 1355 | } |
584 | ss.s.SetTrailer(md) | 1356 | ss.s.SetTrailer(md) |
585 | return | ||
586 | } | 1357 | } |
587 | 1358 | ||
588 | func (ss *serverStream) SendMsg(m interface{}) (err error) { | 1359 | func (ss *serverStream) SendMsg(m interface{}) (err error) { |
@@ -599,29 +1370,50 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { | |||
599 | } | 1370 | } |
600 | ss.mu.Unlock() | 1371 | ss.mu.Unlock() |
601 | } | 1372 | } |
602 | }() | 1373 | if err != nil && err != io.EOF { |
603 | var outPayload *stats.OutPayload | 1374 | st, _ := status.FromError(toRPCErr(err)) |
604 | if ss.statsHandler != nil { | 1375 | ss.t.WriteStatus(ss.s, st) |
605 | outPayload = &stats.OutPayload{} | 1376 | // Non-user specified status was sent out. This should be an error |
606 | } | 1377 | // case (as a server side Cancel maybe). |
607 | out, err := encode(ss.codec, m, ss.cp, ss.cbuf, outPayload) | 1378 | // |
608 | defer func() { | 1379 | // This is not handled specifically now. User will return a final |
609 | if ss.cbuf != nil { | 1380 | // status from the service handler, we will log that error instead. |
610 | ss.cbuf.Reset() | 1381 | // This behavior is similar to an interceptor. |
1382 | } | ||
1383 | if channelz.IsOn() && err == nil { | ||
1384 | ss.t.IncrMsgSent() | ||
611 | } | 1385 | } |
612 | }() | 1386 | }() |
1387 | data, err := encode(ss.codec, m) | ||
1388 | if err != nil { | ||
1389 | return err | ||
1390 | } | ||
1391 | compData, err := compress(data, ss.cp, ss.comp) | ||
613 | if err != nil { | 1392 | if err != nil { |
614 | return err | 1393 | return err |
615 | } | 1394 | } |
616 | if len(out) > ss.maxSendMessageSize { | 1395 | hdr, payload := msgHeader(data, compData) |
617 | return Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(out), ss.maxSendMessageSize) | 1396 | // TODO(dfawley): should we be checking len(data) instead? |
1397 | if len(payload) > ss.maxSendMessageSize { | ||
1398 | return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), ss.maxSendMessageSize) | ||
618 | } | 1399 | } |
619 | if err := ss.t.Write(ss.s, out, &transport.Options{Last: false}); err != nil { | 1400 | if err := ss.t.Write(ss.s, hdr, payload, &transport.Options{Last: false}); err != nil { |
620 | return toRPCErr(err) | 1401 | return toRPCErr(err) |
621 | } | 1402 | } |
622 | if outPayload != nil { | 1403 | if ss.binlog != nil { |
623 | outPayload.SentTime = time.Now() | 1404 | if !ss.serverHeaderBinlogged { |
624 | ss.statsHandler.HandleRPC(ss.s.Context(), outPayload) | 1405 | h, _ := ss.s.Header() |
1406 | ss.binlog.Log(&binarylog.ServerHeader{ | ||
1407 | Header: h, | ||
1408 | }) | ||
1409 | ss.serverHeaderBinlogged = true | ||
1410 | } | ||
1411 | ss.binlog.Log(&binarylog.ServerMessage{ | ||
1412 | Message: data, | ||
1413 | }) | ||
1414 | } | ||
1415 | if ss.statsHandler != nil { | ||
1416 | ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now())) | ||
625 | } | 1417 | } |
626 | return nil | 1418 | return nil |
627 | } | 1419 | } |
@@ -640,22 +1432,55 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { | |||
640 | } | 1432 | } |
641 | ss.mu.Unlock() | 1433 | ss.mu.Unlock() |
642 | } | 1434 | } |
1435 | if err != nil && err != io.EOF { | ||
1436 | st, _ := status.FromError(toRPCErr(err)) | ||
1437 | ss.t.WriteStatus(ss.s, st) | ||
1438 | // Non-user specified status was sent out. This should be an error | ||
1439 | // case (as a server side Cancel maybe). | ||
1440 | // | ||
1441 | // This is not handled specifically now. User will return a final | ||
1442 | // status from the service handler, we will log that error instead. | ||
1443 | // This behavior is similar to an interceptor. | ||
1444 | } | ||
1445 | if channelz.IsOn() && err == nil { | ||
1446 | ss.t.IncrMsgRecv() | ||
1447 | } | ||
643 | }() | 1448 | }() |
644 | var inPayload *stats.InPayload | 1449 | var payInfo *payloadInfo |
645 | if ss.statsHandler != nil { | 1450 | if ss.statsHandler != nil || ss.binlog != nil { |
646 | inPayload = &stats.InPayload{} | 1451 | payInfo = &payloadInfo{} |
647 | } | 1452 | } |
648 | if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, inPayload); err != nil { | 1453 | if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil { |
649 | if err == io.EOF { | 1454 | if err == io.EOF { |
1455 | if ss.binlog != nil { | ||
1456 | ss.binlog.Log(&binarylog.ClientHalfClose{}) | ||
1457 | } | ||
650 | return err | 1458 | return err |
651 | } | 1459 | } |
652 | if err == io.ErrUnexpectedEOF { | 1460 | if err == io.ErrUnexpectedEOF { |
653 | err = Errorf(codes.Internal, io.ErrUnexpectedEOF.Error()) | 1461 | err = status.Errorf(codes.Internal, io.ErrUnexpectedEOF.Error()) |
654 | } | 1462 | } |
655 | return toRPCErr(err) | 1463 | return toRPCErr(err) |
656 | } | 1464 | } |
657 | if inPayload != nil { | 1465 | if ss.statsHandler != nil { |
658 | ss.statsHandler.HandleRPC(ss.s.Context(), inPayload) | 1466 | ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{ |
1467 | RecvTime: time.Now(), | ||
1468 | Payload: m, | ||
1469 | // TODO truncate large payload. | ||
1470 | Data: payInfo.uncompressedBytes, | ||
1471 | Length: len(payInfo.uncompressedBytes), | ||
1472 | }) | ||
1473 | } | ||
1474 | if ss.binlog != nil { | ||
1475 | ss.binlog.Log(&binarylog.ClientMessage{ | ||
1476 | Message: payInfo.uncompressedBytes, | ||
1477 | }) | ||
659 | } | 1478 | } |
660 | return nil | 1479 | return nil |
661 | } | 1480 | } |
1481 | |||
1482 | // MethodFromServerStream returns the method string for the input stream. | ||
1483 | // The returned string is in the format of "/service/method". | ||
1484 | func MethodFromServerStream(stream ServerStream) (string, bool) { | ||
1485 | return Method(stream.Context()) | ||
1486 | } | ||
diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go index decb678..584360f 100644 --- a/vendor/google.golang.org/grpc/tap/tap.go +++ b/vendor/google.golang.org/grpc/tap/tap.go | |||
@@ -21,7 +21,7 @@ | |||
21 | package tap | 21 | package tap |
22 | 22 | ||
23 | import ( | 23 | import ( |
24 | "golang.org/x/net/context" | 24 | "context" |
25 | ) | 25 | ) |
26 | 26 | ||
27 | // Info defines the relevant information needed by the handles. | 27 | // Info defines the relevant information needed by the handles. |
@@ -32,8 +32,20 @@ type Info struct { | |||
32 | // TODO: More to be added. | 32 | // TODO: More to be added. |
33 | } | 33 | } |
34 | 34 | ||
35 | // ServerInHandle defines the function which runs when a new stream is created | 35 | // ServerInHandle defines the function which runs before a new stream is created |
36 | // on the server side. Note that it is executed in the per-connection I/O goroutine(s) instead | 36 | // on the server side. If it returns a non-nil error, the stream will not be |
37 | // of per-RPC goroutine. Therefore, users should NOT have any blocking/time-consuming | 37 | // created and a RST_STREAM will be sent back to the client with REFUSED_STREAM. |
38 | // work in this handle. Otherwise all the RPCs would slow down. | 38 | // The client will receive an RPC error "code = Unavailable, desc = stream |
39 | // terminated by RST_STREAM with error code: REFUSED_STREAM". | ||
40 | // | ||
41 | // It's intended to be used in situations where you don't want to waste the | ||
42 | // resources to accept the new stream (e.g. rate-limiting). And the content of | ||
43 | // the error will be ignored and won't be sent back to the client. For other | ||
44 | // general usages, please use interceptors. | ||
45 | // | ||
46 | // Note that it is executed in the per-connection I/O goroutine(s) instead of | ||
47 | // per-RPC goroutine. Therefore, users should NOT have any | ||
48 | // blocking/time-consuming work in this handle. Otherwise all the RPCs would | ||
49 | // slow down. Also, for the same reason, this handle won't be called | ||
50 | // concurrently by gRPC. | ||
39 | type ServerInHandle func(ctx context.Context, info *Info) (context.Context, error) | 51 | type ServerInHandle func(ctx context.Context, info *Info) (context.Context, error) |
diff --git a/vendor/google.golang.org/grpc/test/bufconn/bufconn.go b/vendor/google.golang.org/grpc/test/bufconn/bufconn.go new file mode 100644 index 0000000..bdb5d81 --- /dev/null +++ b/vendor/google.golang.org/grpc/test/bufconn/bufconn.go | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2017 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | // Package bufconn provides a net.Conn implemented by a buffer and related | ||
20 | // dialing and listening functionality. | ||
21 | package bufconn | ||
22 | |||
23 | import ( | ||
24 | "fmt" | ||
25 | "io" | ||
26 | "net" | ||
27 | "sync" | ||
28 | "time" | ||
29 | ) | ||
30 | |||
31 | // Listener implements a net.Listener that creates local, buffered net.Conns | ||
32 | // via its Accept and Dial method. | ||
33 | type Listener struct { | ||
34 | mu sync.Mutex | ||
35 | sz int | ||
36 | ch chan net.Conn | ||
37 | done chan struct{} | ||
38 | } | ||
39 | |||
40 | var errClosed = fmt.Errorf("Closed") | ||
41 | |||
42 | // Listen returns a Listener that can only be contacted by its own Dialers and | ||
43 | // creates buffered connections between the two. | ||
44 | func Listen(sz int) *Listener { | ||
45 | return &Listener{sz: sz, ch: make(chan net.Conn), done: make(chan struct{})} | ||
46 | } | ||
47 | |||
48 | // Accept blocks until Dial is called, then returns a net.Conn for the server | ||
49 | // half of the connection. | ||
50 | func (l *Listener) Accept() (net.Conn, error) { | ||
51 | select { | ||
52 | case <-l.done: | ||
53 | return nil, errClosed | ||
54 | case c := <-l.ch: | ||
55 | return c, nil | ||
56 | } | ||
57 | } | ||
58 | |||
59 | // Close stops the listener. | ||
60 | func (l *Listener) Close() error { | ||
61 | l.mu.Lock() | ||
62 | defer l.mu.Unlock() | ||
63 | select { | ||
64 | case <-l.done: | ||
65 | // Already closed. | ||
66 | break | ||
67 | default: | ||
68 | close(l.done) | ||
69 | } | ||
70 | return nil | ||
71 | } | ||
72 | |||
73 | // Addr reports the address of the listener. | ||
74 | func (l *Listener) Addr() net.Addr { return addr{} } | ||
75 | |||
76 | // Dial creates an in-memory full-duplex network connection, unblocks Accept by | ||
77 | // providing it the server half of the connection, and returns the client half | ||
78 | // of the connection. | ||
79 | func (l *Listener) Dial() (net.Conn, error) { | ||
80 | p1, p2 := newPipe(l.sz), newPipe(l.sz) | ||
81 | select { | ||
82 | case <-l.done: | ||
83 | return nil, errClosed | ||
84 | case l.ch <- &conn{p1, p2}: | ||
85 | return &conn{p2, p1}, nil | ||
86 | } | ||
87 | } | ||
88 | |||
89 | type pipe struct { | ||
90 | mu sync.Mutex | ||
91 | |||
92 | // buf contains the data in the pipe. It is a ring buffer of fixed capacity, | ||
93 | // with r and w pointing to the offset to read and write, respsectively. | ||
94 | // | ||
95 | // Data is read between [r, w) and written to [w, r), wrapping around the end | ||
96 | // of the slice if necessary. | ||
97 | // | ||
98 | // The buffer is empty if r == len(buf), otherwise if r == w, it is full. | ||
99 | // | ||
100 | // w and r are always in the range [0, cap(buf)) and [0, len(buf)]. | ||
101 | buf []byte | ||
102 | w, r int | ||
103 | |||
104 | wwait sync.Cond | ||
105 | rwait sync.Cond | ||
106 | |||
107 | closed bool | ||
108 | writeClosed bool | ||
109 | } | ||
110 | |||
111 | func newPipe(sz int) *pipe { | ||
112 | p := &pipe{buf: make([]byte, 0, sz)} | ||
113 | p.wwait.L = &p.mu | ||
114 | p.rwait.L = &p.mu | ||
115 | return p | ||
116 | } | ||
117 | |||
118 | func (p *pipe) empty() bool { | ||
119 | return p.r == len(p.buf) | ||
120 | } | ||
121 | |||
122 | func (p *pipe) full() bool { | ||
123 | return p.r < len(p.buf) && p.r == p.w | ||
124 | } | ||
125 | |||
126 | func (p *pipe) Read(b []byte) (n int, err error) { | ||
127 | p.mu.Lock() | ||
128 | defer p.mu.Unlock() | ||
129 | // Block until p has data. | ||
130 | for { | ||
131 | if p.closed { | ||
132 | return 0, io.ErrClosedPipe | ||
133 | } | ||
134 | if !p.empty() { | ||
135 | break | ||
136 | } | ||
137 | if p.writeClosed { | ||
138 | return 0, io.EOF | ||
139 | } | ||
140 | p.rwait.Wait() | ||
141 | } | ||
142 | wasFull := p.full() | ||
143 | |||
144 | n = copy(b, p.buf[p.r:len(p.buf)]) | ||
145 | p.r += n | ||
146 | if p.r == cap(p.buf) { | ||
147 | p.r = 0 | ||
148 | p.buf = p.buf[:p.w] | ||
149 | } | ||
150 | |||
151 | // Signal a blocked writer, if any | ||
152 | if wasFull { | ||
153 | p.wwait.Signal() | ||
154 | } | ||
155 | |||
156 | return n, nil | ||
157 | } | ||
158 | |||
159 | func (p *pipe) Write(b []byte) (n int, err error) { | ||
160 | p.mu.Lock() | ||
161 | defer p.mu.Unlock() | ||
162 | if p.closed { | ||
163 | return 0, io.ErrClosedPipe | ||
164 | } | ||
165 | for len(b) > 0 { | ||
166 | // Block until p is not full. | ||
167 | for { | ||
168 | if p.closed || p.writeClosed { | ||
169 | return 0, io.ErrClosedPipe | ||
170 | } | ||
171 | if !p.full() { | ||
172 | break | ||
173 | } | ||
174 | p.wwait.Wait() | ||
175 | } | ||
176 | wasEmpty := p.empty() | ||
177 | |||
178 | end := cap(p.buf) | ||
179 | if p.w < p.r { | ||
180 | end = p.r | ||
181 | } | ||
182 | x := copy(p.buf[p.w:end], b) | ||
183 | b = b[x:] | ||
184 | n += x | ||
185 | p.w += x | ||
186 | if p.w > len(p.buf) { | ||
187 | p.buf = p.buf[:p.w] | ||
188 | } | ||
189 | if p.w == cap(p.buf) { | ||
190 | p.w = 0 | ||
191 | } | ||
192 | |||
193 | // Signal a blocked reader, if any. | ||
194 | if wasEmpty { | ||
195 | p.rwait.Signal() | ||
196 | } | ||
197 | } | ||
198 | return n, nil | ||
199 | } | ||
200 | |||
201 | func (p *pipe) Close() error { | ||
202 | p.mu.Lock() | ||
203 | defer p.mu.Unlock() | ||
204 | p.closed = true | ||
205 | // Signal all blocked readers and writers to return an error. | ||
206 | p.rwait.Broadcast() | ||
207 | p.wwait.Broadcast() | ||
208 | return nil | ||
209 | } | ||
210 | |||
211 | func (p *pipe) closeWrite() error { | ||
212 | p.mu.Lock() | ||
213 | defer p.mu.Unlock() | ||
214 | p.writeClosed = true | ||
215 | // Signal all blocked readers and writers to return an error. | ||
216 | p.rwait.Broadcast() | ||
217 | p.wwait.Broadcast() | ||
218 | return nil | ||
219 | } | ||
220 | |||
221 | type conn struct { | ||
222 | io.Reader | ||
223 | io.Writer | ||
224 | } | ||
225 | |||
226 | func (c *conn) Close() error { | ||
227 | err1 := c.Reader.(*pipe).Close() | ||
228 | err2 := c.Writer.(*pipe).closeWrite() | ||
229 | if err1 != nil { | ||
230 | return err1 | ||
231 | } | ||
232 | return err2 | ||
233 | } | ||
234 | |||
235 | func (*conn) LocalAddr() net.Addr { return addr{} } | ||
236 | func (*conn) RemoteAddr() net.Addr { return addr{} } | ||
237 | func (c *conn) SetDeadline(t time.Time) error { return fmt.Errorf("unsupported") } | ||
238 | func (c *conn) SetReadDeadline(t time.Time) error { return fmt.Errorf("unsupported") } | ||
239 | func (c *conn) SetWriteDeadline(t time.Time) error { return fmt.Errorf("unsupported") } | ||
240 | |||
241 | type addr struct{} | ||
242 | |||
243 | func (addr) Network() string { return "bufconn" } | ||
244 | func (addr) String() string { return "bufconn" } | ||
diff --git a/vendor/google.golang.org/grpc/trace.go b/vendor/google.golang.org/grpc/trace.go index b419c9e..c1c96de 100644 --- a/vendor/google.golang.org/grpc/trace.go +++ b/vendor/google.golang.org/grpc/trace.go | |||
@@ -31,7 +31,7 @@ import ( | |||
31 | 31 | ||
32 | // EnableTracing controls whether to trace RPCs using the golang.org/x/net/trace package. | 32 | // EnableTracing controls whether to trace RPCs using the golang.org/x/net/trace package. |
33 | // This should only be set before any RPCs are sent or received by this program. | 33 | // This should only be set before any RPCs are sent or received by this program. |
34 | var EnableTracing = true | 34 | var EnableTracing bool |
35 | 35 | ||
36 | // methodFamily returns the trace family for the given method. | 36 | // methodFamily returns the trace family for the given method. |
37 | // It turns "/pkg.Service/GetFoo" into "pkg.Service". | 37 | // It turns "/pkg.Service/GetFoo" into "pkg.Service". |
@@ -76,6 +76,15 @@ func (f *firstLine) String() string { | |||
76 | return line.String() | 76 | return line.String() |
77 | } | 77 | } |
78 | 78 | ||
79 | const truncateSize = 100 | ||
80 | |||
81 | func truncate(x string, l int) string { | ||
82 | if l > len(x) { | ||
83 | return x | ||
84 | } | ||
85 | return x[:l] | ||
86 | } | ||
87 | |||
79 | // payload represents an RPC request or response payload. | 88 | // payload represents an RPC request or response payload. |
80 | type payload struct { | 89 | type payload struct { |
81 | sent bool // whether this is an outgoing payload | 90 | sent bool // whether this is an outgoing payload |
@@ -85,9 +94,9 @@ type payload struct { | |||
85 | 94 | ||
86 | func (p payload) String() string { | 95 | func (p payload) String() string { |
87 | if p.sent { | 96 | if p.sent { |
88 | return fmt.Sprintf("sent: %v", p.msg) | 97 | return truncate(fmt.Sprintf("sent: %v", p.msg), truncateSize) |
89 | } | 98 | } |
90 | return fmt.Sprintf("recv: %v", p.msg) | 99 | return truncate(fmt.Sprintf("recv: %v", p.msg), truncateSize) |
91 | } | 100 | } |
92 | 101 | ||
93 | type fmtStringer struct { | 102 | type fmtStringer struct { |
diff --git a/vendor/google.golang.org/grpc/transport/go16.go b/vendor/google.golang.org/grpc/transport/go16.go deleted file mode 100644 index 7cffee1..0000000 --- a/vendor/google.golang.org/grpc/transport/go16.go +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | // +build go1.6,!go1.7 | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2016 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package transport | ||
22 | |||
23 | import ( | ||
24 | "net" | ||
25 | |||
26 | "google.golang.org/grpc/codes" | ||
27 | |||
28 | "golang.org/x/net/context" | ||
29 | ) | ||
30 | |||
31 | // dialContext connects to the address on the named network. | ||
32 | func dialContext(ctx context.Context, network, address string) (net.Conn, error) { | ||
33 | return (&net.Dialer{Cancel: ctx.Done()}).Dial(network, address) | ||
34 | } | ||
35 | |||
36 | // ContextErr converts the error from context package into a StreamError. | ||
37 | func ContextErr(err error) StreamError { | ||
38 | switch err { | ||
39 | case context.DeadlineExceeded: | ||
40 | return streamErrorf(codes.DeadlineExceeded, "%v", err) | ||
41 | case context.Canceled: | ||
42 | return streamErrorf(codes.Canceled, "%v", err) | ||
43 | } | ||
44 | return streamErrorf(codes.Internal, "Unexpected error from context packet: %v", err) | ||
45 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/go17.go b/vendor/google.golang.org/grpc/transport/go17.go deleted file mode 100644 index 2464e69..0000000 --- a/vendor/google.golang.org/grpc/transport/go17.go +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | // +build go1.7 | ||
2 | |||
3 | /* | ||
4 | * | ||
5 | * Copyright 2016 gRPC authors. | ||
6 | * | ||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | * you may not use this file except in compliance with the License. | ||
9 | * You may obtain a copy of the License at | ||
10 | * | ||
11 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | * | ||
13 | * Unless required by applicable law or agreed to in writing, software | ||
14 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | * See the License for the specific language governing permissions and | ||
17 | * limitations under the License. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | package transport | ||
22 | |||
23 | import ( | ||
24 | "context" | ||
25 | "net" | ||
26 | |||
27 | "google.golang.org/grpc/codes" | ||
28 | |||
29 | netctx "golang.org/x/net/context" | ||
30 | ) | ||
31 | |||
32 | // dialContext connects to the address on the named network. | ||
33 | func dialContext(ctx context.Context, network, address string) (net.Conn, error) { | ||
34 | return (&net.Dialer{}).DialContext(ctx, network, address) | ||
35 | } | ||
36 | |||
37 | // ContextErr converts the error from context package into a StreamError. | ||
38 | func ContextErr(err error) StreamError { | ||
39 | switch err { | ||
40 | case context.DeadlineExceeded, netctx.DeadlineExceeded: | ||
41 | return streamErrorf(codes.DeadlineExceeded, "%v", err) | ||
42 | case context.Canceled, netctx.Canceled: | ||
43 | return streamErrorf(codes.Canceled, "%v", err) | ||
44 | } | ||
45 | return streamErrorf(codes.Internal, "Unexpected error from context packet: %v", err) | ||
46 | } | ||
diff --git a/vendor/google.golang.org/grpc/transport/http2_client.go b/vendor/google.golang.org/grpc/transport/http2_client.go deleted file mode 100644 index 516ea06..0000000 --- a/vendor/google.golang.org/grpc/transport/http2_client.go +++ /dev/null | |||
@@ -1,1369 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2014 gRPC authors. | ||
4 | * | ||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | * you may not use this file except in compliance with the License. | ||
7 | * You may obtain a copy of the License at | ||
8 | * | ||
9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | * | ||
11 | * Unless required by applicable law or agreed to in writing, software | ||
12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | * See the License for the specific language governing permissions and | ||
15 | * limitations under the License. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | package transport | ||
20 | |||
21 | import ( | ||
22 | "bytes" | ||
23 | "io" | ||
24 | "math" | ||
25 | "net" | ||
26 | "strings" | ||
27 | "sync" | ||
28 | "sync/atomic" | ||
29 | "time" | ||
30 | |||
31 | "golang.org/x/net/context" | ||
32 | "golang.org/x/net/http2" | ||
33 | "golang.org/x/net/http2/hpack" | ||
34 | "google.golang.org/grpc/codes" | ||
35 | "google.golang.org/grpc/credentials" | ||
36 | "google.golang.org/grpc/keepalive" | ||
37 | "google.golang.org/grpc/metadata" | ||
38 | "google.golang.org/grpc/peer" | ||
39 | "google.golang.org/grpc/stats" | ||
40 | "google.golang.org/grpc/status" | ||
41 | ) | ||
42 | |||
43 | // http2Client implements the ClientTransport interface with HTTP2. | ||
44 | type http2Client struct { | ||
45 | ctx context.Context | ||
46 | target string // server name/addr | ||
47 | userAgent string | ||
48 | md interface{} | ||
49 | conn net.Conn // underlying communication channel | ||
50 | remoteAddr net.Addr | ||
51 | localAddr net.Addr | ||
52 | authInfo credentials.AuthInfo // auth info about the connection | ||
53 | nextID uint32 // the next stream ID to be used | ||
54 | |||
55 | // writableChan synchronizes write access to the transport. | ||
56 | // A writer acquires the write lock by sending a value on writableChan | ||
57 | // and releases it by receiving from writableChan. | ||
58 | writableChan chan int | ||
59 | // shutdownChan is closed when Close is called. | ||
60 | // Blocking operations should select on shutdownChan to avoid | ||
61 | // blocking forever after Close. | ||
62 | // TODO(zhaoq): Maybe have a channel context? | ||
63 | shutdownChan chan struct{} | ||
64 | // errorChan is closed to notify the I/O error to the caller. | ||
65 | errorChan chan struct{} | ||
66 | // goAway is closed to notify the upper layer (i.e., addrConn.transportMonitor) | ||
67 | // that the server sent GoAway on this transport. | ||
68 | goAway chan struct{} | ||
69 | // awakenKeepalive is used to wake up keepalive when after it has gone dormant. | ||
70 | awakenKeepalive chan struct{} | ||
71 | |||
72 | framer *framer | ||
73 | hBuf *bytes.Buffer // the buffer for HPACK encoding | ||
74 | hEnc *hpack.Encoder // HPACK encoder | ||
75 | |||
76 | // controlBuf delivers all the control related tasks (e.g., window | ||
77 | // updates, reset streams, and various settings) to the controller. | ||
78 | controlBuf *controlBuffer | ||
79 | fc *inFlow | ||
80 | // sendQuotaPool provides flow control to outbound message. | ||
81 | sendQuotaPool *quotaPool | ||
82 | // streamsQuota limits the max number of concurrent streams. | ||
83 | streamsQuota *quotaPool | ||
84 | |||
85 | // The scheme used: https if TLS is on, http otherwise. | ||
86 | scheme string | ||
87 | |||
88 | isSecure bool | ||
89 | |||
90 | creds []credentials.PerRPCCredentials | ||
91 | |||
92 | // Boolean to keep track of reading activity on transport. | ||
93 | // 1 is true and 0 is false. | ||
94 | activity uint32 // Accessed atomically. | ||
95 | kp keepalive.ClientParameters | ||
96 | |||
97 | statsHandler stats.Handler | ||
98 | |||
99 | initialWindowSize int32 | ||
100 | |||
101 | bdpEst *bdpEstimator | ||
102 | outQuotaVersion uint32 | ||
103 | |||
104 | mu sync.Mutex // guard the following variables | ||
105 | state transportState // the state of underlying connection | ||
106 | activeStreams map[uint32]*Stream | ||
107 | // The max number of concurrent streams | ||
108 | maxStreams int | ||
109 | // the per-stream outbound flow control window size set by the peer. | ||
110 | streamSendQuota uint32 | ||
111 | // prevGoAway ID records the Last-Stream-ID in the previous GOAway frame. | ||
112 | prevGoAwayID uint32 | ||
113 | // goAwayReason records the http2.ErrCode and debug data received with the | ||
114 | // GoAway frame. | ||
115 | goAwayReason GoAwayReason | ||
116 | } | ||
117 | |||
118 | func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr string) (net.Conn, error) { | ||
119 | if fn != nil { | ||
120 | return fn(ctx, addr) | ||
121 | } | ||
122 | return dialContext(ctx, "tcp", addr) | ||
123 | } | ||
124 | |||
125 | func isTemporary(err error) bool { | ||
126 | switch err { | ||
127 | case io.EOF: | ||
128 | // Connection closures may be resolved upon retry, and are thus | ||
129 | // treated as temporary. | ||
130 | return true | ||
131 | case context.DeadlineExceeded: | ||
132 | // In Go 1.7, context.DeadlineExceeded implements Timeout(), and this | ||
133 | // special case is not needed. Until then, we need to keep this | ||
134 | // clause. | ||
135 | return true | ||
136 | } | ||
137 | |||
138 | switch err := err.(type) { | ||
139 | case interface { | ||
140 | Temporary() bool | ||
141 | }: | ||
142 | return err.Temporary() | ||
143 | case interface { | ||
144 | Timeout() bool | ||
145 | }: | ||
146 | // Timeouts may be resolved upon retry, and are thus treated as | ||
147 | // temporary. | ||
148 | return err.Timeout() | ||
149 | } | ||
150 | return false | ||
151 | } | ||
152 | |||
153 | // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2 | ||
154 | // and starts to receive messages on it. Non-nil error returns if construction | ||
155 | // fails. | ||
156 | func newHTTP2Client(ctx context.Context, addr TargetInfo, opts ConnectOptions) (_ ClientTransport, err error) { | ||
157 | scheme := "http" | ||
158 | conn, err := dial(ctx, opts.Dialer, addr.Addr) | ||
159 | if err != nil { | ||
160 | if opts.FailOnNonTempDialError { | ||
161 | return nil, connectionErrorf(isTemporary(err), err, "transport: error while dialing: %v", err) | ||
162 | } | ||
163 | return nil, connectionErrorf(true, err, "transport: Error while dialing %v", err) | ||
164 | } | ||
165 | // Any further errors will close the underlying connection | ||
166 | defer func(conn net.Conn) { | ||
167 | if err != nil { | ||
168 | conn.Close() | ||
169 | } | ||
170 | }(conn) | ||
171 | var ( | ||
172 | isSecure bool | ||
173 | authInfo credentials.AuthInfo | ||
174 | ) | ||
175 | if creds := opts.TransportCredentials; creds != nil { | ||
176 | scheme = "https" | ||
177 | conn, authInfo, err = creds.ClientHandshake(ctx, addr.Addr, conn) | ||
178 | if err != nil { | ||
179 | // Credentials handshake errors are typically considered permanent | ||
180 | // to avoid retrying on e.g. bad certificates. | ||
181 | temp := isTemporary(err) | ||
182 | return nil, connectionErrorf(temp, err, "transport: authentication handshake failed: %v", err) | ||
183 | } | ||
184 | isSecure = true | ||
185 | } | ||
186 | kp := opts.KeepaliveParams | ||
187 | // Validate keepalive parameters. | ||
188 | if kp.Time == 0 { | ||
189 | kp.Time = defaultClientKeepaliveTime | ||
190 | } | ||
191 | if kp.Timeout == 0 { | ||
192 | kp.Timeout = defaultClientKeepaliveTimeout | ||
193 | } | ||
194 | dynamicWindow := true | ||
195 | icwz := int32(initialWindowSize) | ||
196 | if opts.InitialConnWindowSize >= defaultWindowSize { | ||
197 | icwz = opts.InitialConnWindowSize | ||
198 | dynamicWindow = false | ||
199 | } | ||
200 | var buf bytes.Buffer | ||
201 | t := &http2Client{ | ||
202 | ctx: ctx, | ||
203 | target: addr.Addr, | ||
204 | userAgent: opts.UserAgent, | ||
205 | md: addr.Metadata, | ||
206 | conn: conn, | ||
207 | remoteAddr: conn.RemoteAddr(), | ||
208 | localAddr: conn.LocalAddr(), | ||
209 | authInfo: authInfo, | ||
210 | // The client initiated stream id is odd starting from 1. | ||
211 | nextID: 1, | ||
212 | writableChan: make(chan int, 1), | ||
213 | shutdownChan: make(chan struct{}), | ||
214 | errorChan: make(chan struct{}), | ||
215 | goAway: make(chan struct{}), | ||
216 | awakenKeepalive: make(chan struct{}, 1), | ||
217 | framer: newFramer(conn), | ||
218 | hBuf: &buf, | ||
219 | hEnc: hpack.NewEncoder(&buf), | ||
220 | controlBuf: newControlBuffer(), | ||
221 | fc: &inFlow{limit: uint32(icwz)}, | ||
222 | sendQuotaPool: newQuotaPool(defaultWindowSize), | ||
223 | scheme: scheme, | ||
224 | state: reachable, | ||
225 | activeStreams: make(map[uint32]*Stream), | ||
226 | isSecure: isSecure, | ||
227 | creds: opts.PerRPCCredentials, | ||
228 | maxStreams: defaultMaxStreamsClient, | ||
229 | streamsQuota: newQuotaPool(defaultMaxStreamsClient), | ||
230 | streamSendQuota: defaultWindowSize, | ||
231 | kp: kp, | ||
232 | statsHandler: opts.StatsHandler, | ||
233 | initialWindowSize: initialWindowSize, | ||
234 | } | ||
235 | if opts.InitialWindowSize >= defaultWindowSize { | ||
236 | t.initialWindowSize = opts.InitialWindowSize | ||
237 | dynamicWindow = false | ||
238 | } | ||
239 | if dynamicWindow { | ||
240 | t.bdpEst = &bdpEstimator{ | ||
241 | bdp: initialWindowSize, | ||
242 | updateFlowControl: t.updateFlowControl, | ||
243 | } | ||
244 | } | ||
245 | // Make sure awakenKeepalive can't be written upon. | ||
246 | // keepalive routine will make it writable, if need be. | ||
247 | t.awakenKeepalive <- struct{}{} | ||
248 | if t.statsHandler != nil { | ||
249 | t.ctx = t.statsHandler.TagConn(t.ctx, &stats.ConnTagInfo{ | ||
250 | RemoteAddr: t.remoteAddr, | ||
251 | LocalAddr: t.localAddr, | ||
252 | }) | ||
253 | connBegin := &stats.ConnBegin{ | ||
254 | Client: true, | ||
255 | } | ||
256 | t.statsHandler.HandleConn(t.ctx, connBegin) | ||
257 | } | ||
258 | // Start the reader goroutine for incoming message. Each transport has | ||
259 | // a dedicated goroutine which reads HTTP2 frame from network. Then it | ||
260 | // dispatches the frame to the corresponding stream entity. | ||
261 | go t.reader() | ||
262 | // Send connection preface to server. | ||
263 | n, err := t.conn.Write(clientPreface) | ||
264 | if err != nil { | ||
265 | t.Close() | ||
266 | return nil, connectionErrorf(true, err, "transport: failed to write client preface: %v", err) | ||
267 | } | ||
268 | if n != len(clientPreface) { | ||
269 | t.Close() | ||
270 | return nil, connectionErrorf(true, err, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) | ||
271 | } | ||
272 | if t.initialWindowSize != defaultWindowSize { | ||
273 | err = t.framer.writeSettings(true, http2.Setting{ | ||
274 | ID: http2.SettingInitialWindowSize, | ||
275 | Val: uint32(t.initialWindowSize), | ||
276 | }) | ||
277 | } else { | ||
278 | err = t.framer.writeSettings(true) | ||
279 | } | ||
280 | if err != nil { | ||
281 | t.Close() | ||
282 | return nil, connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) | ||
283 | } | ||
284 | // Adjust the connection flow control window if needed. | ||
285 | if delta := uint32(icwz - defaultWindowSize); delta > 0 { | ||
286 | if err := t.framer.writeWindowUpdate(true, 0, delta); err != nil { | ||
287 | t.Close() | ||
288 | return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err) | ||
289 | } | ||
290 | } | ||
291 | go t.controller() | ||
292 | if t.kp.Time != infinity { | ||
293 | go t.keepalive() | ||
294 | } | ||
295 | t.writableChan <- 0 | ||
296 | return t, nil | ||
297 | } | ||
298 | |||
299 | func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream { | ||
300 | // TODO(zhaoq): Handle uint32 overflow of Stream.id. | ||
301 | s := &Stream{ | ||
302 | id: t.nextID, | ||
303 | done: make(chan struct{}), | ||
304 | goAway: make(chan struct{}), | ||
305 | method: callHdr.Method, | ||
306 | sendCompress: callHdr.SendCompress, | ||
307 | buf: newRecvBuffer(), | ||
308 | fc: &inFlow{limit: uint32(t.initialWindowSize)}, | ||
309 | sendQuotaPool: newQuotaPool(int(t.streamSendQuota)), | ||
310 | headerChan: make(chan struct{}), | ||
311 | } | ||
312 | t.nextID += 2 | ||
313 | s.requestRead = func(n int) { | ||
314 | t.adjustWindow(s, uint32(n)) | ||
315 | } | ||
316 | // The client side stream context should have exactly the same life cycle with the user provided context. | ||
317 | // That means, s.ctx should be read-only. And s.ctx is done iff ctx is done. | ||
318 | // So we use the original context here instead of creating a copy. | ||
319 | s.ctx = ctx | ||
320 | s.trReader = &transportReader{ | ||
321 | reader: &recvBufferReader{ | ||
322 | ctx: s.ctx, | ||
323 | goAway: s.goAway, | ||
324 | recv: s.buf, | ||
325 | }, | ||
326 | windowHandler: func(n int) { | ||
327 | t.updateWindow(s, uint32(n)) | ||
328 | }, | ||
329 | } | ||
330 | |||
331 | return s | ||
332 | } | ||
333 | |||
334 | // NewStream creates a stream and registers it into the transport as "active" | ||
335 | // streams. | ||
336 | func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) { | ||
337 | pr := &peer.Peer{ | ||
338 | Addr: t.remoteAddr, | ||
339 | } | ||
340 | // Attach Auth info if there is any. | ||
341 | if t.authInfo != nil { | ||
342 | pr.AuthInfo = t.authInfo | ||
343 | } | ||
344 | ctx = peer.NewContext(ctx, pr) | ||
345 | var ( | ||
346 | authData = make(map[string]string) | ||
347 | audience string | ||
348 | ) | ||
349 | // Create an audience string only if needed. | ||
350 | if len(t.creds) > 0 || callHdr.Creds != nil { | ||
351 | // Construct URI required to get auth request metadata. | ||
352 | var port string | ||
353 | if pos := strings.LastIndex(t.target, ":"); pos != -1 { | ||
354 | // Omit port if it is the default one. | ||
355 | if t.target[pos+1:] != "443" { | ||
356 | port = ":" + t.target[pos+1:] | ||
357 | } | ||
358 | } | ||
359 | pos := strings.LastIndex(callHdr.Method, "/") | ||
360 | if pos == -1 { | ||
361 | pos = len(callHdr.Method) | ||
362 | } | ||
363 | audience = "https://" + callHdr.Host + port + callHdr.Method[:pos] | ||
364 | } | ||
365 | for _, c := range t.creds { | ||
366 | data, err := c.GetRequestMetadata(ctx, audience) | ||
367 | if err != nil { | ||
368 | return nil, streamErrorf(codes.Internal, "transport: %v", err) | ||
369 | } | ||
370 | for k, v := range data { | ||
371 | // Capital header names are illegal in HTTP/2. | ||
372 | k = strings.ToLower(k) | ||
373 | authData[k] = v | ||
374 | } | ||
375 | } | ||
376 | callAuthData := make(map[string]string) | ||
377 | // Check if credentials.PerRPCCredentials were provided via call options. | ||
378 | // Note: if these credentials are provided both via dial options and call | ||
379 | // options, then both sets of credentials will be applied. | ||
380 | if callCreds := callHdr.Creds; callCreds != nil { | ||
381 | if !t.isSecure && callCreds.RequireTransportSecurity() { | ||
382 | return nil, streamErrorf(codes.Unauthenticated, "transport: cannot send secure credentials on an insecure conneciton") | ||
383 | } | ||
384 | data, err := callCreds.GetRequestMetadata(ctx, audience) | ||
385 | if err != nil { | ||
386 | return nil, streamErrorf(codes.Internal, "transport: %v", err) | ||
387 | } | ||
388 | for k, v := range data { | ||
389 | // Capital header names are illegal in HTTP/2 | ||
390 | k = strings.ToLower(k) | ||
391 | callAuthData[k] = v | ||
392 | } | ||
393 | } | ||
394 | t.mu.Lock() | ||
395 | if t.activeStreams == nil { | ||
396 | t.mu.Unlock() | ||
397 | return nil, ErrConnClosing | ||
398 | } | ||
399 | if t.state == draining { | ||
400 | t.mu.Unlock() | ||
401 | return nil, ErrStreamDrain | ||
402 | } | ||
403 | if t.state != reachable { | ||
404 | t.mu.Unlock() | ||
405 | return nil, ErrConnClosing | ||
406 | } | ||
407 | t.mu.Unlock() | ||
408 | sq, err := wait(ctx, nil, nil, t.shutdownChan, t.streamsQuota.acquire()) | ||
409 | if err != nil { | ||
410 | return nil, err | ||
411 | } | ||
412 | // Returns the quota balance back. | ||
413 | if sq > 1 { | ||
414 | t.streamsQuota.add(sq - 1) | ||
415 | } | ||
416 | if _, err := wait(ctx, nil, nil, t.shutdownChan, t.writableChan); err != nil { | ||
417 | // Return the quota back now because there is no stream returned to the caller. | ||
418 | if _, ok := err.(StreamError); ok { | ||
419 | t.streamsQuota.add(1) | ||
420 | } | ||
421 | return nil, err | ||
422 | } | ||
423 | t.mu.Lock() | ||
424 | if t.state == draining { | ||
425 | t.mu.Unlock() | ||
426 | t.streamsQuota.add(1) | ||
427 | // Need to make t writable again so that the rpc in flight can still proceed. | ||
428 | t.writableChan <- 0 | ||
429 | return nil, ErrStreamDrain | ||
430 | } | ||
431 | if t.state != reachable { | ||
432 | t.mu.Unlock() | ||
433 | return nil, ErrConnClosing | ||
434 | } | ||
435 | s := t.newStream(ctx, callHdr) | ||
436 | t.activeStreams[s.id] = s | ||
437 | // If the number of active streams change from 0 to 1, then check if keepalive | ||
438 | // has gone dormant. If so, wake it up. | ||
439 | if len(t.activeStreams) == 1 { | ||
440 | select { | ||
441 | case t.awakenKeepalive <- struct{}{}: | ||
442 | t.framer.writePing(false, false, [8]byte{}) | ||
443 | default: | ||
444 | } | ||
445 | } | ||
446 | |||
447 | t.mu.Unlock() | ||
448 | |||
449 | // HPACK encodes various headers. Note that once WriteField(...) is | ||
450 | // called, the corresponding headers/continuation frame has to be sent | ||
451 | // because hpack.Encoder is stateful. | ||
452 | t.hBuf.Reset() | ||
453 | t.hEnc.WriteField(hpack.HeaderField{Name: ":method", Value: "POST"}) | ||
454 | t.hEnc.WriteField(hpack.HeaderField{Name: ":scheme", Value: t.scheme}) | ||
455 | t.hEnc.WriteField(hpack.HeaderField{Name: ":path", Value: callHdr.Method}) | ||
456 | t.hEnc.WriteField(hpack.HeaderField{Name: ":authority", Value: callHdr.Host}) | ||
457 | t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"}) | ||
458 | t.hEnc.WriteField(hpack.HeaderField{Name: "user-agent", Value: t.userAgent}) | ||
459 | t.hEnc.WriteField(hpack.HeaderField{Name: "te", Value: "trailers"}) | ||
460 | |||
461 | if callHdr.SendCompress != "" { | ||
462 | t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) | ||
463 | } | ||
464 | if dl, ok := ctx.Deadline(); ok { | ||
465 | // Send out timeout regardless its value. The server can detect timeout context by itself. | ||
466 | timeout := dl.Sub(time.Now()) | ||
467 | t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-timeout", Value: encodeTimeout(timeout)}) | ||
468 | } | ||
469 | |||
470 | for k, v := range authData { | ||
471 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
472 | } | ||
473 | for k, v := range callAuthData { | ||
474 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
475 | } | ||
476 | var ( | ||
477 | endHeaders bool | ||
478 | ) | ||
479 | if md, ok := metadata.FromOutgoingContext(ctx); ok { | ||
480 | for k, vv := range md { | ||
481 | // HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set. | ||
482 | if isReservedHeader(k) { | ||
483 | continue | ||
484 | } | ||
485 | for _, v := range vv { | ||
486 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | if md, ok := t.md.(*metadata.MD); ok { | ||
491 | for k, vv := range *md { | ||
492 | if isReservedHeader(k) { | ||
493 | continue | ||
494 | } | ||
495 | for _, v := range vv { | ||
496 | t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)}) | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | first := true | ||
501 | bufLen := t.hBuf.Len() | ||
502 | // Sends the headers in a single batch even when they span multiple frames. | ||
503 | for !endHeaders { | ||
504 | size := t.hBuf.Len() | ||
505 | if size > http2MaxFrameLen { | ||
506 | size = http2MaxFrameLen | ||
507 | } else { | ||
508 | endHeaders = true | ||
509 | } | ||
510 | var flush bool | ||
511 | if callHdr.Flush && endHeaders { | ||
512 | flush = true | ||
513 | } | ||
514 | if first { | ||
515 | // Sends a HeadersFrame to server to start a new stream. | ||
516 | p := http2.HeadersFrameParam{ | ||
517 | StreamID: s.id, | ||
518 | BlockFragment: t.hBuf.Next(size), | ||
519 | EndStream: false, | ||
520 | EndHeaders: endHeaders, | ||
521 | } | ||
522 | // Do a force flush for the buffered frames iff it is the last headers frame | ||
523 | // and there is header metadata to be sent. Otherwise, there is flushing until | ||
524 | // the corresponding data frame is written. | ||
525 | err = t.framer.writeHeaders(flush, p) | ||
526 | first = false | ||
527 | } else { | ||
528 | // Sends Continuation frames for the leftover headers. | ||
529 | err = t.framer.writeContinuation(flush, s.id, endHeaders, t.hBuf.Next(size)) | ||
530 | } | ||
531 | if err != nil { | ||
532 | t.notifyError(err) | ||
533 | return nil, connectionErrorf(true, err, "transport: %v", err) | ||
534 | } | ||
535 | } | ||
536 | s.mu.Lock() | ||
537 | s.bytesSent = true | ||
538 | s.mu.Unlock() | ||
539 | |||
540 | if t.statsHandler != nil { | ||
541 | outHeader := &stats.OutHeader{ | ||
542 | Client: true, | ||
543 | WireLength: bufLen, | ||
544 | FullMethod: callHdr.Method, | ||
545 | RemoteAddr: t.remoteAddr, | ||
546 | LocalAddr: t.localAddr, | ||
547 | Compression: callHdr.SendCompress, | ||
548 | } | ||
549 | t.statsHandler.HandleRPC(s.ctx, outHeader) | ||
550 | } | ||
551 | t.writableChan <- 0 | ||
552 | return s, nil | ||
553 | } | ||
554 | |||
555 | // CloseStream clears the footprint of a stream when the stream is not needed any more. | ||
556 | // This must not be executed in reader's goroutine. | ||
557 | func (t *http2Client) CloseStream(s *Stream, err error) { | ||
558 | t.mu.Lock() | ||
559 | if t.activeStreams == nil { | ||
560 | t.mu.Unlock() | ||
561 | return | ||
562 | } | ||
563 | if err != nil { | ||
564 | // notify in-flight streams, before the deletion | ||
565 | s.write(recvMsg{err: err}) | ||
566 | } | ||
567 | delete(t.activeStreams, s.id) | ||
568 | if t.state == draining && len(t.activeStreams) == 0 { | ||
569 | // The transport is draining and s is the last live stream on t. | ||
570 | t.mu.Unlock() | ||
571 | t.Close() | ||
572 | return | ||
573 | } | ||
574 | t.mu.Unlock() | ||
575 | // rstStream is true in case the stream is being closed at the client-side | ||
576 | // and the server needs to be intimated about it by sending a RST_STREAM | ||
577 | // frame. | ||
578 | // To make sure this frame is written to the wire before the headers of the | ||
579 | // next stream waiting for streamsQuota, we add to streamsQuota pool only | ||
580 | // after having acquired the writableChan to send RST_STREAM out (look at | ||
581 | // the controller() routine). | ||
582 | var rstStream bool | ||
583 | var rstError http2.ErrCode | ||
584 | defer func() { | ||
585 | // In case, the client doesn't have to send RST_STREAM to server | ||
586 | // we can safely add back to streamsQuota pool now. | ||
587 | if !rstStream { | ||
588 | t.streamsQuota.add(1) | ||
589 | return | ||
590 | } | ||
591 | t.controlBuf.put(&resetStream{s.id, rstError}) | ||
592 | }() | ||
593 | s.mu.Lock() | ||
594 | rstStream = s.rstStream | ||
595 | rstError = s.rstError | ||
596 | if s.state == streamDone { | ||
597 | s.mu.Unlock() | ||
598 | return | ||
599 | } | ||
600 | if !s.headerDone { | ||
601 | close(s.headerChan) | ||
602 | s.headerDone = true | ||
603 | } | ||
604 | s.state = streamDone | ||
605 | s.mu.Unlock() | ||
606 | if _, ok := err.(StreamError); ok { | ||
607 | rstStream = true | ||
608 | rstError = http2.ErrCodeCancel | ||
609 | } | ||
610 | } | ||
611 | |||
612 | // Close kicks off the shutdown process of the transport. This should be called | ||
613 | // only once on a transport. Once it is called, the transport should not be | ||
614 | // accessed any more. | ||
615 | func (t *http2Client) Close() (err error) { | ||
616 | t.mu.Lock() | ||
617 | if t.state == closing { | ||
618 | t.mu.Unlock() | ||
619 | return | ||
620 | } | ||
621 | if t.state == reachable || t.state == draining { | ||
622 | close(t.errorChan) | ||
623 | } | ||
624 | t.state = closing | ||
625 | t.mu.Unlock() | ||
626 | close(t.shutdownChan) | ||
627 | err = t.conn.Close() | ||
628 | t.mu.Lock() | ||
629 | streams := t.activeStreams | ||
630 | t.activeStreams = nil | ||
631 | t.mu.Unlock() | ||
632 | // Notify all active streams. | ||
633 | for _, s := range streams { | ||
634 | s.mu.Lock() | ||
635 | if !s.headerDone { | ||
636 | close(s.headerChan) | ||
637 | s.headerDone = true | ||
638 | } | ||
639 | s.mu.Unlock() | ||
640 | s.write(recvMsg{err: ErrConnClosing}) | ||
641 | } | ||
642 | if t.statsHandler != nil { | ||
643 | connEnd := &stats.ConnEnd{ | ||
644 | Client: true, | ||
645 | } | ||
646 | t.statsHandler.HandleConn(t.ctx, connEnd) | ||
647 | } | ||
648 | return | ||
649 | } | ||
650 | |||
651 | func (t *http2Client) GracefulClose() error { | ||
652 | t.mu.Lock() | ||
653 | switch t.state { | ||
654 | case unreachable: | ||
655 | // The server may close the connection concurrently. t is not available for | ||
656 | // any streams. Close it now. | ||
657 | t.mu.Unlock() | ||
658 | t.Close() | ||
659 | return nil | ||
660 | case closing: | ||
661 | t.mu.Unlock() | ||
662 | return nil | ||
663 | } | ||
664 | if t.state == draining { | ||
665 | t.mu.Unlock() | ||
666 | return nil | ||
667 | } | ||
668 | t.state = draining | ||
669 | active := len(t.activeStreams) | ||
670 | t.mu.Unlock() | ||
671 | if active == 0 { | ||
672 | return t.Close() | ||
673 | } | ||
674 | return nil | ||
675 | } | ||
676 | |||
677 | // Write formats the data into HTTP2 data frame(s) and sends it out. The caller | ||
678 | // should proceed only if Write returns nil. | ||
679 | // TODO(zhaoq): opts.Delay is ignored in this implementation. Support it later | ||
680 | // if it improves the performance. | ||
681 | func (t *http2Client) Write(s *Stream, data []byte, opts *Options) error { | ||
682 | r := bytes.NewBuffer(data) | ||
683 | var ( | ||
684 | p []byte | ||
685 | oqv uint32 | ||
686 | ) | ||
687 | for { | ||
688 | oqv = atomic.LoadUint32(&t.outQuotaVersion) | ||
689 | if r.Len() > 0 || p != nil { | ||
690 | size := http2MaxFrameLen | ||
691 | // Wait until the stream has some quota to send the data. | ||
692 | sq, err := wait(s.ctx, s.done, s.goAway, t.shutdownChan, s.sendQuotaPool.acquire()) | ||
693 | if err != nil { | ||
694 | return err | ||
695 | } | ||
696 | // Wait until the transport has some quota to send the data. | ||
697 | tq, err := wait(s.ctx, s.done, s.goAway, t.shutdownChan, t.sendQuotaPool.acquire()) | ||
698 | if err != nil { | ||
699 | return err | ||
700 | } | ||
701 | if sq < size { | ||
702 | size = sq | ||
703 | } | ||
704 | if tq < size { | ||
705 | size = tq | ||
706 | } | ||
707 | if p == nil { | ||
708 | p = r.Next(size) | ||
709 | } | ||
710 | ps := len(p) | ||
711 | if ps < sq { | ||
712 | // Overbooked stream quota. Return it back. | ||
713 | s.sendQuotaPool.add(sq - ps) | ||
714 | } | ||
715 | if ps < tq { | ||
716 | // Overbooked transport quota. Return it back. | ||
717 | t.sendQuotaPool.add(tq - ps) | ||
718 | } | ||
719 | } | ||
720 | var ( | ||
721 | endStream bool | ||
722 | forceFlush bool | ||
723 | ) | ||
724 | if opts.Last && r.Len() == 0 { | ||
725 | endStream = true | ||
726 | } | ||
727 | // Indicate there is a writer who is about to write a data frame. | ||
728 | t.framer.adjustNumWriters(1) | ||
729 | // Got some quota. Try to acquire writing privilege on the transport. | ||
730 | if _, err := wait(s.ctx, s.done, s.goAway, t.shutdownChan, t.writableChan); err != nil { | ||
731 | if _, ok := err.(StreamError); ok || err == io.EOF { | ||
732 | // Return the connection quota back. | ||
733 | t.sendQuotaPool.add(len(p)) | ||
734 | } | ||
735 | if t.framer.adjustNumWriters(-1) == 0 { | ||
736 | // This writer is the last one in this batch and has the | ||
737 | // responsibility to flush the buffered frames. It queues | ||
738 | // a flush request to controlBuf instead of flushing directly | ||
739 | // in order to avoid the race with other writing or flushing. | ||
740 | t.controlBuf.put(&flushIO{}) | ||
741 | } | ||
742 | return err | ||
743 | } | ||
744 | select { | ||
745 | case <-s.ctx.Done(): | ||
746 | t.sendQuotaPool.add(len(p)) | ||
747 | if t.framer.adjustNumWriters(-1) == 0 { | ||
748 | t.controlBuf.put(&flushIO{}) | ||
749 | } | ||
750 | t.writableChan <- 0 | ||
751 | return ContextErr(s.ctx.Err()) | ||
752 | default: | ||
753 | } | ||
754 | if oqv != atomic.LoadUint32(&t.outQuotaVersion) { | ||
755 | // InitialWindowSize settings frame must have been received after we | ||
756 | // acquired send quota but before we got the writable channel. | ||
757 | // We must forsake this write. | ||
758 | t.sendQuotaPool.add(len(p)) | ||
759 | s.sendQuotaPool.add(len(p)) | ||
760 | if t.framer.adjustNumWriters(-1) == 0 { | ||
761 | t.controlBuf.put(&flushIO{}) | ||
762 | } | ||
763 | t.writableChan <- 0 | ||
764 | continue | ||
765 | } | ||
766 | if r.Len() == 0 && t.framer.adjustNumWriters(0) == 1 { | ||
767 | // Do a force flush iff this is last frame for the entire gRPC message | ||
768 | // and the caller is the only writer at this moment. | ||
769 | forceFlush = true | ||
770 | } | ||
771 | // If WriteData fails, all the pending streams will be handled | ||
772 | // by http2Client.Close(). No explicit CloseStream() needs to be | ||
773 | // invoked. | ||
774 | if err := t.framer.writeData(forceFlush, s.id, endStream, p); err != nil { | ||
775 | t.notifyError(err) | ||
776 | return connectionErrorf(true, err, "transport: %v", err) | ||
777 | } | ||
778 | p = nil | ||
779 | if t.framer.adjustNumWriters(-1) == 0 { | ||
780 | t.framer.flushWrite() | ||
781 | } | ||
782 | t.writableChan <- 0 | ||
783 | if r.Len() == 0 { | ||
784 | break | ||
785 | } | ||
786 | } | ||
787 | if !opts.Last { | ||
788 | return nil | ||
789 | } | ||
790 | s.mu.Lock() | ||
791 | if s.state != streamDone { | ||
792 | s.state = streamWriteDone | ||
793 | } | ||
794 | s.mu.Unlock() | ||
795 | return nil | ||
796 | } | ||
797 | |||
798 | func (t *http2Client) getStream(f http2.Frame) (*Stream, bool) { | ||
799 | t.mu.Lock() | ||
800 | defer t.mu.Unlock() | ||
801 | s, ok := t.activeStreams[f.Header().StreamID] | ||
802 | return s, ok | ||
803 | } | ||
804 | |||
805 | // adjustWindow sends out extra window update over the initial window size | ||
806 | // of stream if the application is requesting data larger in size than | ||
807 | // the window. | ||
808 | func (t *http2Client) adjustWindow(s *Stream, n uint32) { | ||
809 | s.mu.Lock() | ||
810 | defer s.mu.Unlock() | ||
811 | if s.state == streamDone { | ||
812 | return | ||
813 | } | ||
814 | if w := s.fc.maybeAdjust(n); w > 0 { | ||
815 | // Piggyback conneciton's window update along. | ||
816 | if cw := t.fc.resetPendingUpdate(); cw > 0 { | ||
817 | t.controlBuf.put(&windowUpdate{0, cw, false}) | ||
818 | } | ||
819 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | ||
820 | } | ||
821 | } | ||
822 | |||
823 | // updateWindow adjusts the inbound quota for the stream and the transport. | ||
824 | // Window updates will deliver to the controller for sending when | ||
825 | // the cumulative quota exceeds the corresponding threshold. | ||
826 | func (t *http2Client) updateWindow(s *Stream, n uint32) { | ||
827 | s.mu.Lock() | ||
828 | defer s.mu.Unlock() | ||
829 | if s.state == streamDone { | ||
830 | return | ||
831 | } | ||
832 | if w := s.fc.onRead(n); w > 0 { | ||
833 | if cw := t.fc.resetPendingUpdate(); cw > 0 { | ||
834 | t.controlBuf.put(&windowUpdate{0, cw, false}) | ||
835 | } | ||
836 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | ||
837 | } | ||
838 | } | ||
839 | |||
840 | // updateFlowControl updates the incoming flow control windows | ||
841 | // for the transport and the stream based on the current bdp | ||
842 | // estimation. | ||
843 | func (t *http2Client) updateFlowControl(n uint32) { | ||
844 | t.mu.Lock() | ||
845 | for _, s := range t.activeStreams { | ||
846 | s.fc.newLimit(n) | ||
847 | } | ||
848 | t.initialWindowSize = int32(n) | ||
849 | t.mu.Unlock() | ||
850 | t.controlBuf.put(&windowUpdate{0, t.fc.newLimit(n), false}) | ||
851 | t.controlBuf.put(&settings{ | ||
852 | ack: false, | ||
853 | ss: []http2.Setting{ | ||
854 | { | ||
855 | ID: http2.SettingInitialWindowSize, | ||
856 | Val: uint32(n), | ||
857 | }, | ||
858 | }, | ||
859 | }) | ||
860 | } | ||
861 | |||
862 | func (t *http2Client) handleData(f *http2.DataFrame) { | ||
863 | size := f.Header().Length | ||
864 | var sendBDPPing bool | ||
865 | if t.bdpEst != nil { | ||
866 | sendBDPPing = t.bdpEst.add(uint32(size)) | ||
867 | } | ||
868 | // Decouple connection's flow control from application's read. | ||
869 | // An update on connection's flow control should not depend on | ||
870 | // whether user application has read the data or not. Such a | ||
871 | // restriction is already imposed on the stream's flow control, | ||
872 | // and therefore the sender will be blocked anyways. | ||
873 | // Decoupling the connection flow control will prevent other | ||
874 | // active(fast) streams from starving in presence of slow or | ||
875 | // inactive streams. | ||
876 | // | ||
877 | // Furthermore, if a bdpPing is being sent out we can piggyback | ||
878 | // connection's window update for the bytes we just received. | ||
879 | if sendBDPPing { | ||
880 | t.controlBuf.put(&windowUpdate{0, uint32(size), false}) | ||
881 | t.controlBuf.put(bdpPing) | ||
882 | } else { | ||
883 | if err := t.fc.onData(uint32(size)); err != nil { | ||
884 | t.notifyError(connectionErrorf(true, err, "%v", err)) | ||
885 | return | ||
886 | } | ||
887 | if w := t.fc.onRead(uint32(size)); w > 0 { | ||
888 | t.controlBuf.put(&windowUpdate{0, w, true}) | ||
889 | } | ||
890 | } | ||
891 | // Select the right stream to dispatch. | ||
892 | s, ok := t.getStream(f) | ||
893 | if !ok { | ||
894 | return | ||
895 | } | ||
896 | if size > 0 { | ||
897 | s.mu.Lock() | ||
898 | if s.state == streamDone { | ||
899 | s.mu.Unlock() | ||
900 | return | ||
901 | } | ||
902 | if err := s.fc.onData(uint32(size)); err != nil { | ||
903 | s.rstStream = true | ||
904 | s.rstError = http2.ErrCodeFlowControl | ||
905 | s.finish(status.New(codes.Internal, err.Error())) | ||
906 | s.mu.Unlock() | ||
907 | s.write(recvMsg{err: io.EOF}) | ||
908 | return | ||
909 | } | ||
910 | if f.Header().Flags.Has(http2.FlagDataPadded) { | ||
911 | if w := s.fc.onRead(uint32(size) - uint32(len(f.Data()))); w > 0 { | ||
912 | t.controlBuf.put(&windowUpdate{s.id, w, true}) | ||
913 | } | ||
914 | } | ||
915 | s.mu.Unlock() | ||
916 | // TODO(bradfitz, zhaoq): A copy is required here because there is no | ||
917 | // guarantee f.Data() is consumed before the arrival of next frame. | ||
918 | // Can this copy be eliminated? | ||
919 | if len(f.Data()) > 0 { | ||
920 | data := make([]byte, len(f.Data())) | ||
921 | copy(data, f.Data()) | ||
922 | s.write(recvMsg{data: data}) | ||
923 | } | ||
924 | } | ||
925 | // The server has closed the stream without sending trailers. Record that | ||
926 | // the read direction is closed, and set the status appropriately. | ||
927 | if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) { | ||
928 | s.mu.Lock() | ||
929 | if s.state == streamDone { | ||
930 | s.mu.Unlock() | ||
931 | return | ||
932 | } | ||
933 | s.finish(status.New(codes.Internal, "server closed the stream without sending trailers")) | ||
934 | s.mu.Unlock() | ||
935 | s.write(recvMsg{err: io.EOF}) | ||
936 | } | ||
937 | } | ||
938 | |||
939 | func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) { | ||
940 | s, ok := t.getStream(f) | ||
941 | if !ok { | ||
942 | return | ||
943 | } | ||
944 | s.mu.Lock() | ||
945 | if s.state == streamDone { | ||
946 | s.mu.Unlock() | ||
947 | return | ||
948 | } | ||
949 | if !s.headerDone { | ||
950 | close(s.headerChan) | ||
951 | s.headerDone = true | ||
952 | } | ||
953 | statusCode, ok := http2ErrConvTab[http2.ErrCode(f.ErrCode)] | ||
954 | if !ok { | ||
955 | warningf("transport: http2Client.handleRSTStream found no mapped gRPC status for the received http2 error %v", f.ErrCode) | ||
956 | statusCode = codes.Unknown | ||
957 | } | ||
958 | s.finish(status.Newf(statusCode, "stream terminated by RST_STREAM with error code: %d", f.ErrCode)) | ||
959 | s.mu.Unlock() | ||
960 | s.write(recvMsg{err: io.EOF}) | ||
961 | } | ||
962 | |||
963 | func (t *http2Client) handleSettings(f *http2.SettingsFrame) { | ||
964 | if f.IsAck() { | ||
965 | return | ||
966 | } | ||
967 | var ss []http2.Setting | ||
968 | f.ForeachSetting(func(s http2.Setting) error { | ||
969 | ss = append(ss, s) | ||
970 | return nil | ||
971 | }) | ||
972 | // The settings will be applied once the ack is sent. | ||
973 | t.controlBuf.put(&settings{ack: true, ss: ss}) | ||
974 | } | ||
975 | |||
976 | func (t *http2Client) handlePing(f *http2.PingFrame) { | ||
977 | if f.IsAck() { | ||
978 | // Maybe it's a BDP ping. | ||
979 | if t.bdpEst != nil { | ||
980 | t.bdpEst.calculate(f.Data) | ||
981 | } | ||
982 | return | ||
983 | } | ||
984 | pingAck := &ping{ack: true} | ||
985 | copy(pingAck.data[:], f.Data[:]) | ||
986 | t.controlBuf.put(pingAck) | ||
987 | } | ||
988 | |||
989 | func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { | ||
990 | t.mu.Lock() | ||
991 | if t.state != reachable && t.state != draining { | ||
992 | t.mu.Unlock() | ||
993 | return | ||
994 | } | ||
995 | if f.ErrCode == http2.ErrCodeEnhanceYourCalm { | ||
996 | infof("Client received GoAway with http2.ErrCodeEnhanceYourCalm.") | ||
997 | } | ||
998 | id := f.LastStreamID | ||
999 | if id > 0 && id%2 != 1 { | ||
1000 | t.mu.Unlock() | ||
1001 | t.notifyError(connectionErrorf(true, nil, "received illegal http2 GOAWAY frame: stream ID %d is even", f.LastStreamID)) | ||
1002 | return | ||
1003 | } | ||
1004 | // A client can recieve multiple GoAways from server (look at https://github.com/grpc/grpc-go/issues/1387). | ||
1005 | // The idea is that the first GoAway will be sent with an ID of MaxInt32 and the second GoAway will be sent after an RTT delay | ||
1006 | // with the ID of the last stream the server will process. | ||
1007 | // Therefore, when we get the first GoAway we don't really close any streams. While in case of second GoAway we | ||
1008 | // close all streams created after the second GoAwayId. This way streams that were in-flight while the GoAway from server | ||
1009 | // was being sent don't get killed. | ||
1010 | select { | ||
1011 | case <-t.goAway: // t.goAway has been closed (i.e.,multiple GoAways). | ||
1012 | // If there are multiple GoAways the first one should always have an ID greater than the following ones. | ||
1013 | if id > t.prevGoAwayID { | ||
1014 | t.mu.Unlock() | ||
1015 | t.notifyError(connectionErrorf(true, nil, "received illegal http2 GOAWAY frame: previously recv GOAWAY frame with LastStramID %d, currently recv %d", id, f.LastStreamID)) | ||
1016 | return | ||
1017 | } | ||
1018 | default: | ||
1019 | t.setGoAwayReason(f) | ||
1020 | close(t.goAway) | ||
1021 | t.state = draining | ||
1022 | } | ||
1023 | // All streams with IDs greater than the GoAwayId | ||
1024 | // and smaller than the previous GoAway ID should be killed. | ||
1025 | upperLimit := t.prevGoAwayID | ||
1026 | if upperLimit == 0 { // This is the first GoAway Frame. | ||
1027 | upperLimit = math.MaxUint32 // Kill all streams after the GoAway ID. | ||
1028 | } | ||
1029 | for streamID, stream := range t.activeStreams { | ||
1030 | if streamID > id && streamID <= upperLimit { | ||
1031 | close(stream.goAway) | ||
1032 | } | ||
1033 | } | ||
1034 | t.prevGoAwayID = id | ||
1035 | active := len(t.activeStreams) | ||
1036 | t.mu.Unlock() | ||
1037 | if active == 0 { | ||
1038 | t.Close() | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | // setGoAwayReason sets the value of t.goAwayReason based | ||
1043 | // on the GoAway frame received. | ||
1044 | // It expects a lock on transport's mutext to be held by | ||
1045 | // the caller. | ||
1046 | func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) { | ||
1047 | t.goAwayReason = NoReason | ||
1048 | switch f.ErrCode { | ||
1049 | case http2.ErrCodeEnhanceYourCalm: | ||
1050 | if string(f.DebugData()) == "too_many_pings" { | ||
1051 | t.goAwayReason = TooManyPings | ||
1052 | } | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | func (t *http2Client) GetGoAwayReason() GoAwayReason { | ||
1057 | t.mu.Lock() | ||
1058 | defer t.mu.Unlock() | ||
1059 | return t.goAwayReason | ||
1060 | } | ||
1061 | |||
1062 | func (t *http2Client) handleWindowUpdate(f *http2.WindowUpdateFrame) { | ||
1063 | id := f.Header().StreamID | ||
1064 | incr := f.Increment | ||
1065 | if id == 0 { | ||
1066 | t.sendQuotaPool.add(int(incr)) | ||
1067 | return | ||
1068 | } | ||
1069 | if s, ok := t.getStream(f); ok { | ||
1070 | s.sendQuotaPool.add(int(incr)) | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | // operateHeaders takes action on the decoded headers. | ||
1075 | func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { | ||
1076 | s, ok := t.getStream(frame) | ||
1077 | if !ok { | ||
1078 | return | ||
1079 | } | ||
1080 | s.mu.Lock() | ||
1081 | s.bytesReceived = true | ||
1082 | s.mu.Unlock() | ||
1083 | var state decodeState | ||
1084 | if err := state.decodeResponseHeader(frame); err != nil { | ||
1085 | s.mu.Lock() | ||
1086 | if !s.headerDone { | ||
1087 | close(s.headerChan) | ||
1088 | s.headerDone = true | ||
1089 | } | ||
1090 | s.mu.Unlock() | ||
1091 | s.write(recvMsg{err: err}) | ||
1092 | // Something wrong. Stops reading even when there is remaining. | ||
1093 | return | ||
1094 | } | ||
1095 | |||
1096 | endStream := frame.StreamEnded() | ||
1097 | var isHeader bool | ||
1098 | defer func() { | ||
1099 | if t.statsHandler != nil { | ||
1100 | if isHeader { | ||
1101 | inHeader := &stats.InHeader{ | ||
1102 | Client: true, | ||
1103 | WireLength: int(frame.Header().Length), | ||
1104 | } | ||
1105 | t.statsHandler.HandleRPC(s.ctx, inHeader) | ||
1106 | } else { | ||
1107 | inTrailer := &stats.InTrailer{ | ||
1108 | Client: true, | ||
1109 | WireLength: int(frame.Header().Length), | ||
1110 | } | ||
1111 | t.statsHandler.HandleRPC(s.ctx, inTrailer) | ||
1112 | } | ||
1113 | } | ||
1114 | }() | ||
1115 | |||
1116 | s.mu.Lock() | ||
1117 | if !endStream { | ||
1118 | s.recvCompress = state.encoding | ||
1119 | } | ||
1120 | if !s.headerDone { | ||
1121 | if !endStream && len(state.mdata) > 0 { | ||
1122 | s.header = state.mdata | ||
1123 | } | ||
1124 | close(s.headerChan) | ||
1125 | s.headerDone = true | ||
1126 | isHeader = true | ||
1127 | } | ||
1128 | if !endStream || s.state == streamDone { | ||
1129 | s.mu.Unlock() | ||
1130 | return | ||
1131 | } | ||
1132 | |||
1133 | if len(state.mdata) > 0 { | ||
1134 | s.trailer = state.mdata | ||
1135 | } | ||
1136 | s.finish(state.status()) | ||
1137 | s.mu.Unlock() | ||
1138 | s.write(recvMsg{err: io.EOF}) | ||
1139 | } | ||
1140 | |||
1141 | func handleMalformedHTTP2(s *Stream, err error) { | ||
1142 | s.mu.Lock() | ||
1143 | if !s.headerDone { | ||
1144 | close(s.headerChan) | ||
1145 | s.headerDone = true | ||
1146 | } | ||
1147 | s.mu.Unlock() | ||
1148 | s.write(recvMsg{err: err}) | ||
1149 | } | ||
1150 | |||
1151 | // reader runs as a separate goroutine in charge of reading data from network | ||
1152 | // connection. | ||
1153 | // | ||
1154 | // TODO(zhaoq): currently one reader per transport. Investigate whether this is | ||
1155 | // optimal. | ||
1156 | // TODO(zhaoq): Check the validity of the incoming frame sequence. | ||
1157 | func (t *http2Client) reader() { | ||
1158 | // Check the validity of server preface. | ||
1159 | frame, err := t.framer.readFrame() | ||
1160 | if err != nil { | ||
1161 | t.notifyError(err) | ||
1162 | return | ||
1163 | } | ||
1164 | atomic.CompareAndSwapUint32(&t.activity, 0, 1) | ||
1165 | sf, ok := frame.(*http2.SettingsFrame) | ||
1166 | if !ok { | ||
1167 | t.notifyError(err) | ||
1168 | return | ||
1169 | } | ||
1170 | t.handleSettings(sf) | ||
1171 | |||
1172 | // loop to keep reading incoming messages on this transport. | ||
1173 | for { | ||
1174 | frame, err := t.framer.readFrame() | ||
1175 | atomic.CompareAndSwapUint32(&t.activity, 0, 1) | ||
1176 | if err != nil { | ||
1177 | // Abort an active stream if the http2.Framer returns a | ||
1178 | // http2.StreamError. This can happen only if the server's response | ||
1179 | // is malformed http2. | ||
1180 | if se, ok := err.(http2.StreamError); ok { | ||
1181 | t.mu.Lock() | ||
1182 | s := t.activeStreams[se.StreamID] | ||
1183 | t.mu.Unlock() | ||
1184 | if s != nil { | ||
1185 | // use error detail to provide better err message | ||
1186 | handleMalformedHTTP2(s, streamErrorf(http2ErrConvTab[se.Code], "%v", t.framer.errorDetail())) | ||
1187 | } | ||
1188 | continue | ||
1189 | } else { | ||
1190 | // Transport error. | ||
1191 | t.notifyError(err) | ||
1192 | return | ||
1193 | } | ||
1194 | } | ||
1195 | switch frame := frame.(type) { | ||
1196 | case *http2.MetaHeadersFrame: | ||
1197 | t.operateHeaders(frame) | ||
1198 | case *http2.DataFrame: | ||
1199 | t.handleData(frame) | ||
1200 | case *http2.RSTStreamFrame: | ||
1201 | t.handleRSTStream(frame) | ||
1202 | case *http2.SettingsFrame: | ||
1203 | t.handleSettings(frame) | ||
1204 | case *http2.PingFrame: | ||
1205 | t.handlePing(frame) | ||
1206 | case *http2.GoAwayFrame: | ||
1207 | t.handleGoAway(frame) | ||
1208 | case *http2.WindowUpdateFrame: | ||
1209 | t.handleWindowUpdate(frame) | ||
1210 | default: | ||
1211 | errorf("transport: http2Client.reader got unhandled frame type %v.", frame) | ||
1212 | } | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | func (t *http2Client) applySettings(ss []http2.Setting) { | ||
1217 | for _, s := range ss { | ||
1218 | switch s.ID { | ||
1219 | case http2.SettingMaxConcurrentStreams: | ||
1220 | // TODO(zhaoq): This is a hack to avoid significant refactoring of the | ||
1221 | // code to deal with the unrealistic int32 overflow. Probably will try | ||
1222 | // to find a better way to handle this later. | ||
1223 | if s.Val > math.MaxInt32 { | ||
1224 | s.Val = math.MaxInt32 | ||
1225 | } | ||
1226 | t.mu.Lock() | ||
1227 | ms := t.maxStreams | ||
1228 | t.maxStreams = int(s.Val) | ||
1229 | t.mu.Unlock() | ||
1230 | t.streamsQuota.add(int(s.Val) - ms) | ||
1231 | case http2.SettingInitialWindowSize: | ||
1232 | t.mu.Lock() | ||
1233 | for _, stream := range t.activeStreams { | ||
1234 | // Adjust the sending quota for each stream. | ||
1235 | stream.sendQuotaPool.add(int(s.Val) - int(t.streamSendQuota)) | ||
1236 | } | ||
1237 | t.streamSendQuota = s.Val | ||
1238 | t.mu.Unlock() | ||
1239 | atomic.AddUint32(&t.outQuotaVersion, 1) | ||
1240 | } | ||
1241 | } | ||
1242 | } | ||
1243 | |||
1244 | // controller running in a separate goroutine takes charge of sending control | ||
1245 | // frames (e.g., window update, reset stream, setting, etc.) to the server. | ||
1246 | func (t *http2Client) controller() { | ||
1247 | for { | ||
1248 | select { | ||
1249 | case i := <-t.controlBuf.get(): | ||
1250 | t.controlBuf.load() | ||
1251 | select { | ||
1252 | case <-t.writableChan: | ||
1253 | switch i := i.(type) { | ||
1254 | case *windowUpdate: | ||
1255 | t.framer.writeWindowUpdate(i.flush, i.streamID, i.increment) | ||
1256 | case *settings: | ||
1257 | if i.ack { | ||
1258 | t.framer.writeSettingsAck(true) | ||
1259 | t.applySettings(i.ss) | ||
1260 | } else { | ||
1261 | t.framer.writeSettings(true, i.ss...) | ||
1262 | } | ||
1263 | case *resetStream: | ||
1264 | // If the server needs to be to intimated about stream closing, | ||
1265 | // then we need to make sure the RST_STREAM frame is written to | ||
1266 | // the wire before the headers of the next stream waiting on | ||
1267 | // streamQuota. We ensure this by adding to the streamsQuota pool | ||
1268 | // only after having acquired the writableChan to send RST_STREAM. | ||
1269 | t.streamsQuota.add(1) | ||
1270 | t.framer.writeRSTStream(true, i.streamID, i.code) | ||
1271 | case *flushIO: | ||
1272 | t.framer.flushWrite() | ||
1273 | case *ping: | ||
1274 | if !i.ack { | ||
1275 | t.bdpEst.timesnap(i.data) | ||
1276 | } | ||
1277 | t.framer.writePing(true, i.ack, i.data) | ||
1278 | default: | ||
1279 | errorf("transport: http2Client.controller got unexpected item type %v\n", i) | ||
1280 | } | ||
1281 | t.writableChan <- 0 | ||
1282 | continue | ||
1283 | case <-t.shutdownChan: | ||
1284 | return | ||
1285 | } | ||
1286 | case <-t.shutdownChan: | ||
1287 | return | ||
1288 | } | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | // keepalive running in a separate goroutune makes sure the connection is alive by sending pings. | ||
1293 | func (t *http2Client) keepalive() { | ||
1294 | p := &ping{data: [8]byte{}} | ||
1295 | timer := time.NewTimer(t.kp.Time) | ||
1296 | for { | ||
1297 | select { | ||
1298 | case <-timer.C: | ||
1299 | if atomic.CompareAndSwapUint32(&t.activity, 1, 0) { | ||
1300 | timer.Reset(t.kp.Time) | ||
1301 | continue | ||
1302 | } | ||
1303 | // Check if keepalive should go dormant. | ||
1304 | t.mu.Lock() | ||
1305 | if len(t.activeStreams) < 1 && !t.kp.PermitWithoutStream { | ||
1306 | // Make awakenKeepalive writable. | ||
1307 | <-t.awakenKeepalive | ||
1308 | t.mu.Unlock() | ||
1309 | select { | ||
1310 | case <-t.awakenKeepalive: | ||
1311 | // If the control gets here a ping has been sent | ||
1312 | // need to reset the timer with keepalive.Timeout. | ||
1313 | case <-t.shutdownChan: | ||
1314 | return | ||
1315 | } | ||
1316 | } else { | ||
1317 | t.mu.Unlock() | ||
1318 | // Send ping. | ||
1319 | t.controlBuf.put(p) | ||
1320 | } | ||
1321 | |||
1322 | // By the time control gets here a ping has been sent one way or the other. | ||
1323 | timer.Reset(t.kp.Timeout) | ||
1324 | select { | ||
1325 | case <-timer.C: | ||
1326 | if atomic.CompareAndSwapUint32(&t.activity, 1, 0) { | ||
1327 | timer.Reset(t.kp.Time) | ||
1328 | continue | ||
1329 | } | ||
1330 | t.Close() | ||
1331 | return | ||
1332 | case <-t.shutdownChan: | ||
1333 | if !timer.Stop() { | ||
1334 | <-timer.C | ||
1335 | } | ||
1336 | return | ||
1337 | } | ||
1338 | case <-t.shutdownChan: | ||
1339 | if !timer.Stop() { | ||
1340 | <-timer.C | ||
1341 | } | ||
1342 | return | ||
1343 | } | ||
1344 | } | ||
1345 | } | ||
1346 | |||
1347 | func (t *http2Client) Error() <-chan struct{} { | ||
1348 | return t.errorChan | ||
1349 | } | ||
1350 | |||
1351 | func (t *http2Client) GoAway() <-chan struct{} { | ||
1352 | return t.goAway | ||
1353 | } | ||
1354 | |||
1355 | func (t *http2Client) notifyError(err error) { | ||
1356 | t.mu.Lock() | ||
1357 | // make sure t.errorChan is closed only once. | ||
1358 | if t.state == draining { | ||
1359 | t.mu.Unlock() | ||
1360 | t.Close() | ||
1361 | return | ||
1362 | } | ||
1363 | if t.state == reachable { | ||
1364 | t.state = unreachable | ||
1365 | close(t.errorChan) | ||
1366 | infof("transport: http2Client.notifyError got notified that the client transport was broken %v.", err) | ||
1367 | } | ||
1368 | t.mu.Unlock() | ||
1369 | } | ||
diff --git a/vendor/google.golang.org/grpc/naming/go18.go b/vendor/google.golang.org/grpc/version.go index b5a0f84..45eace5 100644 --- a/vendor/google.golang.org/grpc/naming/go18.go +++ b/vendor/google.golang.org/grpc/version.go | |||
@@ -1,8 +1,6 @@ | |||
1 | // +build go1.8 | ||
2 | |||
3 | /* | 1 | /* |
4 | * | 2 | * |
5 | * Copyright 2017 gRPC authors. | 3 | * Copyright 2018 gRPC authors. |
6 | * | 4 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. | 6 | * you may not use this file except in compliance with the License. |
@@ -18,11 +16,7 @@ | |||
18 | * | 16 | * |
19 | */ | 17 | */ |
20 | 18 | ||
21 | package naming | 19 | package grpc |
22 | |||
23 | import "net" | ||
24 | 20 | ||
25 | var ( | 21 | // Version is the current grpc version. |
26 | lookupHost = net.DefaultResolver.LookupHost | 22 | const Version = "1.18.0" |
27 | lookupSRV = net.DefaultResolver.LookupSRV | ||
28 | ) | ||
diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh new file mode 100644 index 0000000..94a5064 --- /dev/null +++ b/vendor/google.golang.org/grpc/vet.sh | |||
@@ -0,0 +1,141 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | if [[ `uname -a` = *"Darwin"* ]]; then | ||
4 | echo "It seems you are running on Mac. This script does not work on Mac. See https://github.com/grpc/grpc-go/issues/2047" | ||
5 | exit 1 | ||
6 | fi | ||
7 | |||
8 | set -ex # Exit on error; debugging enabled. | ||
9 | set -o pipefail # Fail a pipe if any sub-command fails. | ||
10 | |||
11 | die() { | ||
12 | echo "$@" >&2 | ||
13 | exit 1 | ||
14 | } | ||
15 | |||
16 | # Check to make sure it's safe to modify the user's git repo. | ||
17 | if git status --porcelain | read; then | ||
18 | die "Uncommitted or untracked files found; commit changes first" | ||
19 | fi | ||
20 | |||
21 | if [[ -d "${GOPATH}/src" ]]; then | ||
22 | die "\${GOPATH}/src (${GOPATH}/src) exists; this script will delete it." | ||
23 | fi | ||
24 | |||
25 | # Undo any edits made by this script. | ||
26 | cleanup() { | ||
27 | rm -rf "${GOPATH}/src" | ||
28 | git reset --hard HEAD | ||
29 | } | ||
30 | trap cleanup EXIT | ||
31 | |||
32 | fail_on_output() { | ||
33 | tee /dev/stderr | (! read) | ||
34 | } | ||
35 | |||
36 | PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}" | ||
37 | |||
38 | if [[ "$1" = "-install" ]]; then | ||
39 | # Check for module support | ||
40 | if go help mod >& /dev/null; then | ||
41 | go install \ | ||
42 | golang.org/x/lint/golint \ | ||
43 | golang.org/x/tools/cmd/goimports \ | ||
44 | honnef.co/go/tools/cmd/staticcheck \ | ||
45 | github.com/client9/misspell/cmd/misspell \ | ||
46 | github.com/golang/protobuf/protoc-gen-go | ||
47 | else | ||
48 | # Ye olde `go get` incantation. | ||
49 | # Note: this gets the latest version of all tools (vs. the pinned versions | ||
50 | # with Go modules). | ||
51 | go get -u \ | ||
52 | golang.org/x/lint/golint \ | ||
53 | golang.org/x/tools/cmd/goimports \ | ||
54 | honnef.co/go/tools/cmd/staticcheck \ | ||
55 | github.com/client9/misspell/cmd/misspell \ | ||
56 | github.com/golang/protobuf/protoc-gen-go | ||
57 | fi | ||
58 | if [[ -z "${VET_SKIP_PROTO}" ]]; then | ||
59 | if [[ "${TRAVIS}" = "true" ]]; then | ||
60 | PROTOBUF_VERSION=3.3.0 | ||
61 | PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip | ||
62 | pushd /home/travis | ||
63 | wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME} | ||
64 | unzip ${PROTOC_FILENAME} | ||
65 | bin/protoc --version | ||
66 | popd | ||
67 | elif ! which protoc > /dev/null; then | ||
68 | die "Please install protoc into your path" | ||
69 | fi | ||
70 | fi | ||
71 | exit 0 | ||
72 | elif [[ "$#" -ne 0 ]]; then | ||
73 | die "Unknown argument(s): $*" | ||
74 | fi | ||
75 | |||
76 | # - Ensure all source files contain a copyright message. | ||
77 | git ls-files "*.go" | xargs grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" 2>&1 | fail_on_output | ||
78 | |||
79 | # - Make sure all tests in grpc and grpc/test use leakcheck via Teardown. | ||
80 | (! grep 'func Test[^(]' *_test.go) | ||
81 | (! grep 'func Test[^(]' test/*.go) | ||
82 | |||
83 | # - Do not import math/rand for real library code. Use internal/grpcrand for | ||
84 | # thread safety. | ||
85 | git ls-files "*.go" | xargs grep -l '"math/rand"' 2>&1 | (! grep -v '^examples\|^stress\|grpcrand') | ||
86 | |||
87 | # - Ensure all ptypes proto packages are renamed when importing. | ||
88 | git ls-files "*.go" | (! xargs grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/") | ||
89 | |||
90 | # - Check imports that are illegal in appengine (until Go 1.11). | ||
91 | # TODO: Remove when we drop Go 1.10 support | ||
92 | go list -f {{.Dir}} ./... | xargs go run test/go_vet/vet.go | ||
93 | |||
94 | # - gofmt, goimports, golint (with exceptions for generated code), go vet. | ||
95 | gofmt -s -d -l . 2>&1 | fail_on_output | ||
96 | goimports -l . 2>&1 | fail_on_output | ||
97 | golint ./... 2>&1 | (! grep -vE "(_mock|\.pb)\.go:") | ||
98 | go tool vet -all . | ||
99 | |||
100 | # - Check that generated proto files are up to date. | ||
101 | if [[ -z "${VET_SKIP_PROTO}" ]]; then | ||
102 | PATH="/home/travis/bin:${PATH}" make proto && \ | ||
103 | git status --porcelain 2>&1 | fail_on_output || \ | ||
104 | (git status; git --no-pager diff; exit 1) | ||
105 | fi | ||
106 | |||
107 | # - Check that our module is tidy. | ||
108 | if go help mod >& /dev/null; then | ||
109 | go mod tidy && \ | ||
110 | git status --porcelain 2>&1 | fail_on_output || \ | ||
111 | (git status; git --no-pager diff; exit 1) | ||
112 | fi | ||
113 | |||
114 | # - Collection of static analysis checks | ||
115 | ### HACK HACK HACK: Remove once staticcheck works with modules. | ||
116 | # Make a symlink in ${GOPATH}/src to its ${GOPATH}/pkg/mod equivalent for every package we use. | ||
117 | for x in $(find "${GOPATH}/pkg/mod" -name '*@*' | grep -v \/mod\/cache\/); do | ||
118 | pkg="$(echo ${x#"${GOPATH}/pkg/mod/"} | cut -f1 -d@)"; | ||
119 | # If multiple versions exist, just use the existing one. | ||
120 | if [[ -L "${GOPATH}/src/${pkg}" ]]; then continue; fi | ||
121 | mkdir -p "$(dirname "${GOPATH}/src/${pkg}")"; | ||
122 | ln -s $x "${GOPATH}/src/${pkg}"; | ||
123 | done | ||
124 | ### END HACK HACK HACK | ||
125 | |||
126 | # TODO(menghanl): fix errors in transport_test. | ||
127 | staticcheck -go 1.9 -ignore ' | ||
128 | balancer.go:SA1019 | ||
129 | balancer_test.go:SA1019 | ||
130 | clientconn_test.go:SA1019 | ||
131 | balancer/roundrobin/roundrobin_test.go:SA1019 | ||
132 | benchmark/benchmain/main.go:SA1019 | ||
133 | internal/transport/handler_server.go:SA1019 | ||
134 | internal/transport/handler_server_test.go:SA1019 | ||
135 | internal/transport/transport_test.go:SA2002 | ||
136 | stats/stats_test.go:SA1019 | ||
137 | test/channelz_test.go:SA1019 | ||
138 | test/end2end_test.go:SA1019 | ||
139 | test/healthcheck_test.go:SA1019 | ||
140 | ' ./... | ||
141 | misspell -error . | ||